0

Let's say I have a controller which handles requests such as www.xyz.com/api/<someParam>. This is my controller, and my Service:

@Controller
public class MyController {

   @Autowired MyService service;

   @RequestMapping(value = "/api/{someParam}", method = RequestMethod.GET)  
   public String processRequest(
       @PathVariable("someParam") String someParam) {
          return service.processRequest(someParam);     
   }
}

@Service
public class MyService {
   @Autowired APICaller apiCaller;

   public String processRequest(someParam){
      SomeObj obj = apiCaller.callApi();
      // do something with obj
      // return response;
   }
}

Based on the param passed in the URL, I need to call some API, do some processing to the API response, and return it. All these APIs have different processing.

Let's say the APICaller interface is like this:

@Service
public interface APICaller {
    public SomeObj callAPI();
}

@Service
public class ABC implements APICaller {
    @Override
    public SomeObj callAPI() {
         // calls some REST api, does some processing to response and returns SomeObj
    }
}

@Service
public class XYZ implements APICaller {
    @Override
    public SomeObj callAPI() {
         // calls some SOAP api, does some processing to response and returns SomeObj
    }
}

So if the param in the url is 'abc', I need to call ABCImpl. And if it is 'xyz', then I need to call XYZImpl. What should I do in the MyService class to instantiate the proper implementation? I might have multiple implementations based on the param, not just these two.

Thanks.

drunkenfist
  • 2,958
  • 12
  • 39
  • 73
  • 1
    suppose you use `@Qualifier("beanName")` . Refer this [post](http://stackoverflow.com/questions/35509558/handling-several-implementations-of-one-spring-bean-interface-in-one-class-field) and it may be helpful. – Rajith Pemabandu May 04 '17 at 23:36
  • Check this post : https://dzone.com/articles/spring-injecting-lists-maps – phanin May 05 '17 at 00:00

1 Answers1

0

Define a named Map of beans in your configuration class.

@SpringBootApplication
public class Application {

    @Bean
    ABC abc() {
        return new ABC();
    }

    @Bean
    XYZ xyz() {
        return new XYZ();
    }

    @Bean(name="apis")
    Map<String, APICaller> apis() {
        Map<String, APICaller> map = new HashMap<>();
        map.put("xmz", xyz());
        map.put("abc", abc());
        return map;
    }
}

Then inject it as follows:

@Service
public class MyService {
      @Resource(name="apis")
      Map<String, APICaller> apis;

      public String processRequest(String param){
         apis.get(param).callApi();
         // do required null checks before calling callApi()
         // do something with obj
         // return response;
      }
}

Update

As per you comment if you still wanted the dependencies of APICaller be autowired, this is how to to do it with @Bean

@Bean
ABC abc(DependancyBean1 bean2) {
    return new ABC(bean1);
}

@Bean
XYZ xyz(DependancyBean2 bean2) {
    return new XYZ(bean2);
}
Fahim Farook
  • 1,482
  • 2
  • 14
  • 38
  • Thx, but if I return a `new ABC()`, then it will not be part of the Spring managed context, which means I cannot use any Spring annotations such as `@Autowired` within the class. That's the main problem. – drunkenfist May 08 '17 at 21:24
  • It's still be a spring bean. You have to inject (i.e. programmetically with Java using setters) the dependencies during bean initialization (i.e. in the configuration class above). Or you can autowire with a parameter in the bean method. Answer updated. – Fahim Farook May 09 '17 at 07:02