3

I have an interface that has two implementations, and I'd like to conditionally inject either of the two implementations in a spring boot service.

The point is that the eligible implementation should be picked up based on the request message (JSON mapped to a POJO).

My searches leaded me to implement a FactoryBean to control selecting between those two implementations, and to keep the factory telling spring that the beans are not singleton (by returning false for the isSingleton method).

But if this is the right way, I am still not sure how to get the request message to check it and return the right bean.

Can you please tell me if I am on the right track for what I am trying to attain?

=============

UPDATE

I do not want to pollute my code and deal with managing the relation between my service and the dependencies' implementation in the service.

Considering that I will need to deal with more implementations in the future, I need my service to care only about its responsibility.

  1. I need my service to have only one reference of the generic interface and deal with it in an abstracted way.
  2. I need to find a spring-based way to choose the right implementation for each request based on a condition that is derived from the request itself, and inject it in the service.
2
  • Why don't wire applicationcontext and then use getBean(RequiredClass.class) to set the field? Commented Nov 1, 2018 at 8:50
  • Because I do not want to pollute my code. Consider the case when I have more types in the future, then I have to update my service again. Commented Nov 6, 2018 at 14:47

3 Answers 3

5

One option is to inject both beans and conditionally pick the required bean. You can autowire classes implementing same interface into a Map.

Following example uses a factory class to hide the conditional check.

@Component("type1") public class Type1 implements SomeInterface{} @Component("type2") public class Type2 implements SomeInterface{} @Component public class MyTypeFactory { @Autowired private Map<String, SomeInterface> typesMap; public SomeInterface getInstance(String condition){ return typesMap.get(condition); } } @Component public class MyService { @Autowired private MyTypeFactory factory; public void method(String input){ factory.getInstance(input).callRequiredMethod(); } } 
Sign up to request clarification or add additional context in comments.

Comments

1

You could @Autowire both beans in the controller and decided based on the request which one to return.

Consider the below interface:

public interface MyInterface { ... } 

Sample config:

@Configuration public class MyConfig { @Bean("first") public MyInterface firstBean() { ... } @Bean("second") public MyInterface secondBean() { ... } } 

Sample controller:

@RestController public class MyController { @Autowire @Qualifier("first") public MyInterface first; @Autowire @Qualifier("second") public MyInterface second; @GetMapping public MyInterface doStuff(@RequestBody body) { if(shouldReturnFirst(body)){ return first; } else { return second; } } } 

Note that you should most likely not do it this way though, but have a single service, say MyService that should implement this logic for you.

@Component public class MyService { public MyInterface doStuff(body) { if(shouldReturnFirst(body)){ // build your response here } else { // build your response here } } } 

And just delegate to the service from the controller

@GetMapping public MyInterface doStuff(@RequestBody body) { return myService.doStuff(body); } 

1 Comment

Well, I'd like to have only one instance at any time. I need spring to inject the right instance at anytime based on a condition derived from the request. I would consider when I have 3 or 4 types then I need to modify my service again, which I do not want
1

Spring has a concept of Conditional Bean...

Have a look here https://www.intertech.com/Blog/spring-4-conditional-bean-configuration/

1 Comment

I thought it could help, but it seems related to fill the context in at startup and this of course should work well for all prototype beans. Can it be used similarly with beans that would be scoped as Request?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.