Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot bean conditional on @ConfigurationProperties value

Spring Boot gives us typed configuration objects using the @ConfigurationProperties annotation. One of the advantages is getting property name completion in the IDE for free when using the Spring Boot annotation processor. Another would be: validation.

Now, I'd like to make a bean conditional on the value of a property. Actually, I have two implementations of an interface and this property tells me which one should be used. I could implement it like this:

ImplementationA.java

@Component
@ConditionalOnProperty(name = "foo.bar", havingValue = "a")
public class ImplementationA implements SomeInterface { ... }

ImplementationB.java

@Component
@ConditionalOnProperty(name = "foo.bar", havingValue = "b")
public class ImplementationB implements SomeInterface { ... }

application.yml

foo:
  bar: "a"

However, I'd then lose the advantage of typed configuration. So I'd like to declare this property in a @ConfigurationProperties object:

FooProperties.java

@ConfigurationProperties(prefix = "foo")
public class FooProperties {

    private String bar;


    public String getBar() { ... }

    public void setBar(String bar) { ... }
}

This would still work, but when I declare a default value for bar in this class, it would obviously not be picked up by @ConditionalOnProperty as this annotation operates against the Environment directly (as designed). So perhaps it'd be best not to mix these concepts.

So the question is...

Would there be a way to have a conditional bean based on a value in a @ConfigurationProperties object? Preferable using some @Conditional annotation and without creating a @Configuration bean, as that would mean boilerplate code.

like image 346
P44T Avatar asked Mar 07 '18 13:03

P44T


People also ask

Can we have condition based presence or absence of specific bean in spring boot?

36.3.The @ConditionalOnBean and @ConditionalOnMissingBean annotations allow configurations to be skipped based on the presence or absence of specific beans. You can use the value attribute to specify beans by type, or name to specify beans by name.

How do you conditionally load beans?

It allows to load beans conditionally depending on a certain environment property: @Configuration @ConditionalOnProperty( value="module. enabled", havingValue = "true", matchIfMissing = true) class CrossCuttingConcernModule { ... } The CrossCuttingConcernModule is only loaded if the module.

How do you use a spring conditional Bean?

Conditions based on a Bean definition are present in Spring Application context. Conditions based on a Bean object are present in Spring Application context. Conditions based on some or all Bean properties values. Conditions based on some Resources are present in current Spring Application Context or not.


2 Answers

It might not be as sexy but a potential solution could be to Autowire your Configuration into a SomeInterfaceConfiguration that creates provides the service implementation based on the FooProperties.

i.e.

@Configuration
public class SomeInterfaceConfiguration {

    @Bean
    @Autowired
    public SomeInterface someInterface(FooProperties fooProperties){
        if("a".equals(fooProperties.getBar()){
            return SomeInterfaceImplementationA();
        } else {
            return SomeInterfaceImplementationB();
        }
    }
}

Another option is to use profiles but it is different to your desired solution. i.e. Have a default implementation.

@Component
public class ImplementationA 

@Profile("b")
@Primary
@Component
public class ImplementationB
like image 179
JJdev Avatar answered Oct 18 '22 21:10

JJdev


As proposed here, you could create the ConfigurationProperties object manually in your @Conditional like this:

import org.springframework.boot.context.properties.bind.Binder
...
YourConfigurationPropertiesClass config = Binder.get(context.getEnvironment())
.bind("your.properties.prefix", YourConfigurationPropertiesClass.class).orElse(null);
like image 1
user462982 Avatar answered Oct 18 '22 20:10

user462982