Annotiation combinbation of @ConfigurationProperties @DefaultValue @ConditionalOnProperty

Viewed 23

I got a class (more specifically, a record) MyappProperties that is annotated with @ConfigurationProperties that has a lot of configuration options. The are several inner classes (more specifically, inner records) in the class that hold configuration options that are specific to a certain functionality of my application. One of the configuration options, writerImplementation, within one of the inner classes has a default value annotated with @DefaultValue:

@ConfigurationProperties(prefix = "myapp", ignoreUnknownFields = false)
public record MyappProperties(
...
  @DefaultValue ConfigForJob configForJob
  ) {
  ...
  public record ConfigForJob (
  @DefaultValue("MongoTemplate") String writerImplementation
  ) {
  ...
  }
}

I want to use the value of the configuration option writerImplementation to conditionally make a Spring Bean available within the application context depending on the value of the configuration option:

@Bean
@Autowired
@ConditionalOnProperty(name = "myapp.config-for-job.writer-implementation", havingValue = "MongoTemplate")
public Tasklet mongoTemplateTasklet(MongoTemplate mongoTemplate) {
...
}

@Bean
@Autowired
@ConditionalOnProperty(name = "myapp.config-for-job.writer-implementation", havingValue = "MongoRepository")
public Tasklet mongoRepositoryTasklet(MongoRepository mongoRepository) {
...
}

This, however, does not to work. The application fails to start with the message that there isn't a Bean mongoTemplateTasklet available. If I manually set the value for the property with the key myapp.config-for-job.writer-implementation (that is, by putting it in application.properties or command line with -Dmyapp.config-for-job.writer-implementation=MongoTemplate) it works fine.

So it seems like the default value set via the @DefaultValue annotation is not taken up by Spring (or not taken up in time to be available for evaluating the @ConditionalOnProperty annotation).

Any help is much appreciated :)

1 Answers

So it seems like the default value set via the @DefaultValue annotation is not taken up by Spring (or not taken up in time to be available for evaluating the @ConditionalOnProperty annotation).

That's correct. Both @ConfigurationProperties and @ConditionalOnProperty use the application context's Environment as the source of property values and one has no effect on the other.

When binding to a @ConfigurationProperties bean, @DefaultValue is used to specify a value when the environment does not contain a value for the property. It only applies to this specific binding of the property.

putting it in application.properties or command line with -Dmyapp.config-for-job.writer-implementation=MongoTemplate) it works fine

This works because you have set the value MongoTemplate so that it appears in the application context's environment. It can then be found by both @ConfigurationProperties and @ConditionalOnProperty.

You may want to use matchIfMissing on @ConditionalOnProperty:

@ConditionalOnProperty(name = "myapp.config-for-job.writer-implementation", havingValue = "MongoTemplate", matchIfMissing = true)

This will cause the condition to match if myapp.config-for-job.writer-implementation has been set to MongoTemplate or if it hasn't been set at all.

Related