@ConfigurationProperties(prefix = "validateconfig") and @Component work with org.springframework.boot:spring-boot-autoconfigure:2.2.2.RELEASE: the config bean's fields get populated.

However, if you add @Validated and org.springframework.boot:spring-boot-starter-validation:2.2.2.RELEASE, then the config bean is not populated anymore.

An example to reproduce:

git clone https://github.com/peter-kehl/validate-config-bug-report
cd validate-config-bug-report
./gradlew run

Output (the last two lines - conf value and another conf value show the problem):

 :: Spring Boot ::        (v2.2.2.RELEASE)

2020-01-11 22:34:01.812  INFO 7637 --- [           main] your.pack.App                            : Starting App on spectre with PID 7637 (/home/pkehl/validate-config-java/build/classes/java/main started by pkehl in /home/pkehl/validate-config-java)
2020-01-11 22:34:01.817  INFO 7637 --- [           main] your.pack.App                            : No active profile set, falling back to default profiles: default
2020-01-11 22:34:02.791  INFO 7637 --- [           main] your.pack.App                            : Started App in 1.545 seconds (JVM running for 2.014)
conf is of class class your.pack.Conf$$EnhancerBySpringCGLIB$$f1724790
conf value: null
another conf value: null

To see how the same config bean works without spring-boot-starter-validation, edit build.gradle, comment out the first compile statement, uncomment the second compile statement. Then ./gradlew clean run. The output is similar to the above, except for:

conf is of class class your.pack.Conf
conf value: validateconfigvalue
another conf value: anothervalidateconfigvalue

Potentially related to https://github.com/spring-projects/spring-boot/issues/8173 or https://github.com/spring-cloud/spring-cloud-commons/issues/177.

(Also reported recently at https://stackoverflow.com/questions/55471653/spring-validated-annotation-prevents-configurationproproperties-value-injectio#comment97662035_55471653

If JDK version matters, I'm on OpenJDK 1.8.0_232-b09, 64-Bit Server VM (build 25.232-b09, mixed mode)).

Comment From: wilkinsona

Thanks very much for providing a sample. The problem that you're seeing is a side-effect of the use of CGLib proxies for validation.

The CGLib proxy is a sub-class of your Conf class. This sub-classing shadows the value and another fields that you're accessing directly in your main method:

System.out.println( "conf value: " +conf.value );
System.out.println( "another conf value: " +conf.another );

This is retrieving the value and another fields on the proxy which are unaffected by the configuration property binding which sets the fields (via your setter methods) on the proxy's target.

You can fix your problem by using the getter methods instead:

System.out.println( "conf value: " +conf.getValue() );
System.out.println( "another conf value: " +conf.getAnother() );

You will see the expected values

conf value: validateconfigvalue
another conf value: anothervalidateconfigvalue

This change also has the added benefit of improving encapsulation as those fields can now be made private.

I've opened a Spring Framework issue to see if a change can be made to the documentation to note the side-effects of @Validated and its proxying.