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.