I have an interface IInterface.java like below:
public interface IInterface {
void printIt();
}
And there are two implementation classes for this: ImplementationA.java and ImplementationB.java
@Component
public class ImplementationA implements IInterface {
@Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
@Component
public class ImplementationB implements IInterface {
@Override
public void printIt() {
System.out.println("Inside ImplementationB");
}
}
Now I have a listener class, which has this IInterface as a member:
@Component
@AllArgsConstructor
public class Listener {
IInterface iInterface;
public void doStuff(){
iInterface.printIt();
}
}
Now, my requirement is to inject either of ImplementationA.java or ImplementationB.java in the iInterface member of Listener.java based on certain condition.
After some research I started using the @Conditional annotation.
I added two classes ConditionA.java and ConditionB.java:
public class ConditionA implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return false;
}
}
public class ConditionB implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return true;
}
}
And I also changed my implementation classes as below(added the Conditional annotation):
@Component
@Conditional(ConditionA.class)
public class ImplementationA implements IInterface {
@Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
@Component
@Conditional(ConditionB.class)
public class ImplementationB implements IInterface {
@Override
public void printIt() {
System.out.println("Inside ImplementationA");
}
}
This seems to work like a charm for me. Whichever implementation class I need to inject I just return true from its corresponding Condition class and return false from rest of the implementation class's Condition class.
However this next part is where I am facing the challenge:
So from the above solution, I was hardcoding the return true or return false from the matches method of the corresponding Condition class. What if I need to return a dynamic value based on another component.
Lets say I have a spring Component class MyCustomConfig which has a member customFlag and if this member is set to true, we need to inject ImplementationA.class.
I had tried the below(made the class @Component and also autowired MyCustomConfig):
@Component
public class ConditionA implements Condition {
@Autowired
MyCustomConfig myCustomConfig;
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
return myCustomConfig.getCustomFlag();
}
}
However this simply does not work. myCustomConfig is not autowired and I get a null pointer exception.
Could someone please help me with this.