I am developing a shared component where all the configuration classes are registered using spring.factories.

The library provides some generic error handler implemented as a @ControllerAdvice.

The current implementation of @ControllerAdvice forces me to place the annotation on the class (see below) which makes it error prone. If the user of my component decides to use overly broad classpath scan (hypothetical situation and a bad practice) it will result in the GlobalExceptionHandler being registered multiple times.

@Configuration
public class SharedErrorHandlerConfiguration {

    @Bean
    SharedExceptionHandler sharedExceptionHandler() {
        return new SharedExceptionHandler();
    }
}
// ...

@ControllerAdvice
public class SharedExceptionHandler {
    // ...
}

I would like to register the controller advice using factory method -- for example:

@Configuration
public class SharedErrorHandlerConfiguration {

    @Bean
    @ControllerAdvice
    SharedExceptionHandler sharedExceptionHandler() {
        return new SharedExceptionHandler();
    }
}
// ...
// No annotation here
public class SharedExceptionHandler {
    // ...
}

Could you please change the target of the @ControllerAdvice annotation from @Target(ElementType.TYPE) to @Target({ElementType.TYPE, ElementType.METHOD}) to support controller advice defined using factory method?

Comment From: sbrannen

Could you please change the target of the @ControllerAdvice annotation from @Target(ElementType.TYPE) to @Target({ElementType.TYPE, ElementType.METHOD}) to support controller advice defined using factory method?

Although @ControllerAdvice may not be declared on a method (by design), there's nothing stopping you from creating your own custom annotation like the following.

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@ControllerAdvice
public @interface MyControllerAdvice {
}

If you use that in your example, it works as you would expect.

@Configuration
public class SharedErrorHandlerConfiguration {

    @Bean
    @MyControllerAdvice
    SharedExceptionHandler sharedExceptionHandler() {
        return new SharedExceptionHandler();
    }
}
// ...
// No annotation here
public class SharedExceptionHandler {
    // ...
}

⚠️ Please note that the use of @ControllerAdvice as a meta-annotation like in the above example is not an officially supported feature. Thus, although it works now, it may not work in the future.

Comment From: bclozel

I fail to understand how enabling this would prevent mistakes when developers configure classpath scanning in your library package. With this, your @Configuration class would be scanned and parsed anyway.

Sorry it took us so long to get to your issue; if you're still struggling with such issues, maybe giving a better picture of your library and its configuration setup would help us think about other solutions.

In the meantime, I'll close this issue as we are declining the proposed solution.