0

I have the following situation:

@Configuration
@ConfigurationProperties(prefix = "my.prefix")
@ConditionalOnProperty(value = "my.prefix.should-enable", havingValue = "true")
@RequiredArgsConstructor // lombok
public class MyConf {


  @Setter
  private Map<String, SettingOverride> overrides = Collections.emptyMap();
  private final RestTemplate restTemplate;

  @Data
  public static class SettingOverride {
  
    private final boolean enabled;
  }
}

And the following configuration (enabled only for a specific profile via application-profilename.yml):

---
my:
  prefix:
    should-enable: true
    overrides:
      SOME_SETTING:
        enabled: true

The RestTemplate bean is successfully injected, yet the my overrides Map is always empty. A few days ago when I last tested this code, this approach seemed to work.

Interestingly, I found this bit in the reference documentation:

We recommend that @ConfigurationProperties only deal with the environment and, in particular, does not inject other beans from the context. For corner cases, setter injection can be used or any of the *Aware interfaces provided by the framework (such as EnvironmentAware if you need access to the Environment). If you still want to inject other beans using the constructor, the configuration properties bean must be annotated with @Component and use JavaBean-based property binding.

which makes me think that this approach should never have worked (I'm unable to figure out why it even worked, as alternative approaches to the above have all failed).

Trying to make my @Configuration class inject the RestTemplate via e.g. ApplicationContextAware and a default constructor, as suggested in the above documentation, does not work either.

Since this is a test configuration class, it would be ideal if all corresponding properties and structures would be in a single class.

A different configuration class which uses other properties, e.g. (note: no injected beans) :

@Data // lombok
@Configuration
@ConditionalOnProperty(value = "my.other-prefix.should-enable", havingValue = "true")
@ConfigurationProperties(prefix = "my.other-prefix")
public class MyOtherConf {

  private String someValue;
  private Map<String, String> settings = Collections.emptyMap();

}

with a config of:

---
my:
  other-prefix:
    should-enable: true
    settings:
      another-value: "anothervalue"

seems to work without issues. What am I doing wrong?

filpa
  • 3,651
  • 8
  • 52
  • 91
  • AFAIK you cannot map to object type from properties file, only to primitives (String, integer, boolean and some others). As a workaround you can implicitly define setter method that takes a string value and converts it to your desired object – Nick Feb 07 '22 at 13:57
  • (Un)fortunately, that's not the case here. The [reference docs](https://docs.spring.io/spring-boot/docs/2.6.3/reference/htmlsingle/#features.external-config.typesafe-configuration-properties.merging-complex-types) have an explicit example of configuring a `Map` using `@ConfigurationProperties`. – filpa Feb 07 '22 at 14:22
  • Try to use `new LinkedHashMap<>()` as suggested in docs OR remove `@Configuration` and add `@Data` on top of your first example – Nick Feb 07 '22 at 14:53

0 Answers0