javaspring-bootspring-boot-configuration

Use of configuration properties in @Configuration classes


Is it expected that configuration properties classes should be usable within @Configuration classes.

Environment

My Code

application-local.properties:

s3.bucketName=test-bucket

Configuration Properties

@Validated
@ConfigurationProperties(prefix = "s3")
public class S3ConfigurationProperties {

    @NotBlank
    private String bucketName;

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(final String bucketName) {
        this.bucketName = bucketName;
    }
}

Configuration Class

@Configuration
@Profile("local")
@EnableConfigurationProperties(S3ConfigurationProperties.class)
public class LocalS3Configuration {

    @Autowired
    private S3ConfigurationProperties properties;

    @Value("${s3.bucketName}")
    private String bucket;

    @Bean(destroyMethod = "shutdown")
    public AmazonS3 amazonS3(@Value("${local.s3.endpoint}") final String s3Endpoint, @Value("${s3.bucketName}") final String bucketName) {
        // use properties...
        final String bucketInjectedToMethod = bucketName; // works
        final String bucketInjectedViaProperties = properties.getBucketName(); // null
        final String bucketInjectedInClass = bucket; // null

    }

}

Observed Behaviour

If I inject the S3ConfigurationProperties as a field to the configuration class or an argument to the amazonS3 method the instance is non-null, but the bucketName property within it is null.

Injecting the string to the class via @Value is also null.

The only way I can get it to work is to use the method argument annotated as @Value with a string.

Is this expected behaviour or possibly a bug?


Solution

  • In your case it is not necessary to use @EnableConfigurationProperties. You can put @Configuration in S3ConfigurationProperties:

    @Configuration
    @ConfigurationProperties(prefix = "s3")
    public class S3ConfigurationProperties {
    
        private String bucketName;
    
        //getter and setter
    }
    

    So, now you can inject it in LocalS3Configuration:

    @Profile("local")
    @Configuration
    public class LocalS3Configuration {
    
        @Autowired
        private S3ConfigurationProperties properties;
    
        @Value(("${s3.bucketName}"))
        private String bucketName;
    
        @Bean(destroyMethod = "shutdown")
        public AmazonS3 amazonS3() {
    
            final String bucketInjectedToMethod = bucketName;
            final String bucketInjectedViaProperties = properties.getBucketName();
            ...
        }
    }
    

    The annotation @Configuration registers the class as a bean and allows you to inject it in another bean.