Zed
Zed

Reputation: 5921

Defining bean with two possible implementations

So far, I had a very simple bean definition that looked like this:

@Bean
@Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
    return new ImplementationOne();
}

However, I now have situation where additional implementation class has been added, let's call it ImplementationTwo, which needs to be used instead of ImplementationOne when the option is enabled in configuration file.

So what I need is something like this:

@Bean
@Conditional(value=ConditionClass.class)
SomeInterface myMethodImpl(){
    return context.getEnvironment().getProperty("optionEnabled") ? new 
   ImplementationOne() : new ImplementationTwo();
}

Basically a way to instantiate correct implementation at bean definition time based on the configuration value. Is this possible and can anyone please provide an example? Thanks

Upvotes: 3

Views: 81

Answers (2)

sirain
sirain

Reputation: 1168

It is possible to implement this without using @Conditional.

Assuming you have a Interface SomeInterface and two implementations ImplOne ImplTwo:

SomeInterface.java

public interface SomeInterface {
    void someMethod();
}

ImplOne.java

public class ImplOne implements SomeInterface{
    @Override
    public void someMethod() {
       // do something
    }
}

ImplTwo.java

public class ImplTwo implements SomeInterface{
    @Override
    public void someMethod() {
       // do something else
    }
}

Then you can control which implementation is used in a configuration class like this:

MyConfig.java

@Configuration
public class MyConfig {

    @Autowired
    private ApplicationContext context;

    @Bean
    public SomeInterface someInterface() {
        if (this.context.getEnvironment().getProperty("implementation") != null) {
            return new ImplementationOne();
        } else {
            return new ImplementationTwo();
        }
    }
}

Make sure that the component scan of spring finds MyConfig. Then you can use @Autowired to inject the right implementation anywhere else in your code.

Upvotes: 2

HypnoZ
HypnoZ

Reputation: 55

I think you are doing it wrong.

You should use @Conditional() on your implementation and not on your Interface.

Here is how I would do it :

The interface you will use on your code.

MyInterface.java

public interface MyInterface {
   void myMethod();
}

The first implementation :

MyInterfaceImplOne.java

@Bean
@Conditional(MyInterfaceImplOneCondition.class)
public class MyInterfaceImplOne implements MyInterface {
   void myMethod(){
     // dosmthg
    }
}

MyInterfaceImplOneCondition.java

public class MyInterfaceImplOneCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
       return context.getEnvironment().getProperty("optionEnabled")
    }
}

And for the 2nd implementation :

MyInterfaceImplTwo.java

@Bean
@Conditional(MyInterfaceImplTwoCondition.class)
public class MyInterfaceImplTwo implements MyInterface {
   void myMethod(){
     // dosmthg 2
    }
}

MyInterfaceImplTwoCondition.java

public class MyInterfaceImplTwoCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
       return !context.getEnvironment().getProperty("optionEnabled")
    }
}

In that case, you now just have to call the interface, and Spring will inject the bean corresponding to the right condition.

Hope it is what you are looking for, and I was clear enough!

Upvotes: 1

Related Questions