I followed the Spring official document to define MethodValidationPostProcessor
for bean validation. But I am triggering the below warning:
2024-05-30T17:53:41.988-04:00 WARN 74724 --- [demo] [ main] trationDelegate$BeanPostProcessorChecker : Bean 'appConfig' of type [com.example.demo.AppConfig$$SpringCGLIB$$0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [validationPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead.
To reproduce it, see https://github.com/ozooxo/spring-jakarta-validation-post-processors-warning
* Commit #1 is solely generated by spring starter.
* Commit #2 defines the MethodValidationPostProcessor
bean following the doc.
then if I ./gradlew bootRun
I'll see the above warning.
It seems that a similar problem has been coming up before in ~2017: * https://github.com/spring-projects/spring-boot/issues/9416 * https://github.com/spring-projects/spring-framework/issues/20188 * https://github.com/spring-projects/spring-framework/issues/20362
but it has been coming back.
Comment From: quaff
Have you tried adding @JvmStatic
on fun validationPostProcessor()
?
Comment From: sbrannen
Have you tried adding
@JvmStatic
onfun validationPostProcessor()
?
@ozooxo, please try what @quaff suggested and let us know if that gets rid of the warning for you.
Comment From: snicoll
The warning is as follows:
Bean 'appConfig' of type [com.example.demo.AppConfig$$SpringCGLIB$$0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying). The currently created BeanPostProcessor [validationPostProcessor] is declared through a non-static factory method on that class; consider declaring it as static instead.
The documentation is wrong, that Java example should have the static keyword. We'll get that fixed but, as others have said, please read the warning in the log. I don't know how to achieve that with Kotlin though.
As for the sample demo, if you're using Spring Boot, you don't need to register that bean as the auto-configuration does that already.
Comment From: sbrannen
I don't know how to achieve that with Kotlin though.
I think it would look like this:
@Configuration
class AppConfig {
companion object {
@JvmStatic
@Bean
fun validationPostProcessor(): MethodValidationPostProcessor {
return MethodValidationPostProcessor()
}
}
}
Comment From: snicoll
Yes, I am aware how @JvmStatic
works. Have you tried it?
@sdeleuze offered to look why the code above doesn't work.
Comment From: ozooxo
Enn.... I just tried @JvmStatic
@Configuration
class AppConfig {
@JvmStatic
@Bean
fun validationPostProcessor(): MethodValidationPostProcessor {
return MethodValidationPostProcessor()
}
}
````
but got an error
```bash
$ ./gradlew bootRun
> Task :compileKotlin FAILED
e: file:///Users/cynthia.qiu/Workspace/spring-jakarta-validation-post-processors-warning/src/main/kotlin/com/example/demo/AppConfig.kt:11:5 Only members in named objects and companion objects can be annotated with '@JvmStatic'
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':compileKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
> Compilation error. See log for more details
Also by reading https://www.baeldung.com/spring-not-eligible-for-auto-proxying the route cause is this bean cannot be created at startup time, and we should add @Lazy
somewhere (similar to what the ~2017 issues were talking about) instead of what suggested by the error message itself (to turn the method static).
Comment From: ozooxo
Also, put the bean into a companion object
doesn't work either.
@Configuration
class AppConfig {
companion object {
@JvmStatic
@Bean
fun validationPostProcessor(): MethodValidationPostProcessor {
return MethodValidationPostProcessor()
}
}
}
./gradlew bootRun
> Task :bootRun FAILED
...
2024-05-31T09:35:37.230-04:00 WARN 68850 --- [demo] [ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'validationPostProcessor' defined in class path resource [com/example/demo/AppConfig.class]: Cannot register bean definition [Root bean: class [com.example.demo.AppConfig]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=validationPostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [com/example/demo/AppConfig.class]] for bean 'validationPostProcessor' since there is already [Root bean: class [null]; scope=; abstract=false; lazyInit=null; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=com.example.demo.AppConfig$Companion; factoryMethodName=validationPostProcessor; initMethodNames=null; destroyMethodNames=[(inferred)]; defined in class path resource [com/example/demo/AppConfig$Companion.class]] bound.
2024-05-31T09:35:37.237-04:00 INFO 68850 --- [demo] [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2024-05-31T09:35:37.245-04:00 ERROR 68850 --- [demo] [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'validationPostProcessor', defined in class path resource [com/example/demo/AppConfig.class], could not be registered. A bean with that name has already been defined in class path resource [com/example/demo/AppConfig$Companion.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
FAILURE: Build failed with an exception.
Comment From: ozooxo
As for the sample demo, if you're using Spring Boot, you don't need to register that bean as the auto-configuration does that already.
I am using Spring boot, and remove this bean can get rid of the warning. However,
- For unit tests to cover
@Validated
and@Valid
, only@SpringBootTest
instead of@ExtendWith(SpringExtension::class)
can work. That makes sense because the auto-configured bean is not in my@Import
list. - Guess then I can no longer customize the post processor e.g.
processor.setAdaptConstraintViolations(true)
.
To see this, I have commit #3 and in it the testInsertWithInvalidEmail()
test can raise ConstraintViolationException
as expected. And with commit #4 in order for the tests to still pass, I need @SpringBootTest
.
Comment From: sdeleuze
Documentation fixed for the Java use case. Declaring BeanPostProcessor
beans is (surprisingly) not possible yet with Kotlin but this will be supported as of 6.2 via #32946. With previous versions, please use Java classes as a workaround.