1

I have some services implementing same Interface. I want to use service dynamically according to a paramater from database.

I would like use CDI annotation but if not possible please tell me how i can achieve it ? a factory ?

We have several providers with service associated and following the rule in DB we will use service or other

Service1 implements IService1, IGeneralService{

public void run(){...};}

Service2 implements IService2, IGeneralService{

public void run(){...};}

then i will use it according to DB parameter like a country or other.

public class Test{
    @IGeneralService service;

public void getRunMethod(String numberService){
      service.run() (here it run the right service)
}
}

something like that. Any idea ?

cyril
  • 872
  • 6
  • 29
  • I think the best approach is the factory. You will call a createInstance, and the factory decides (including the DB data) what implementation returns – David SK Sep 12 '19 at 15:11
  • getRunMethod looks a lot like a factory, no? – Robert Moskal Sep 12 '19 at 15:55
  • it was a pseudo exemple but yes i know only with factory but witth producer or annotation CDI it is more sexy ^^ – cyril Sep 12 '19 at 17:39
  • Possible duplicate of [How to programmatically inject a Java CDI managed bean into a local variable in a (static) method](https://stackoverflow.com/questions/24798529/how-to-programmatically-inject-a-java-cdi-managed-bean-into-a-local-variable-in) – Kukeltje Sep 13 '19 at 18:56
  • not same title but finality yes – cyril Sep 16 '19 at 06:14

4 Answers4

1

Yes, your test class looks a lot like a factory. Keeping on with what you have, it might look like this:

public class Test{
    @IGeneralService service0;
    @IGeneralService service1;

    public void getRunMethod(String numberService){
      if(numberService == '0')
          service0.run() 
      if(numberService == '1')
          service1.run() 
    }
}

You can get fancier in terms of how you manage that list of services (a map, a list). But the drawback here might be that you have to inject each of your services explicitly.

You could also go another route and inject the BeanManager into your factory:

public class Test{
    @Inject
    BeanManager bm;

    public void getRunMethod(String numberService){
        IGeneralService svc = (IGeneralService) bm.getBeans(numberService).iterator().next();
        svc.run();
    }
}

And now you don't need to explicitly inject each service.

Those are the two basic approached you can use here. Which is better depends on your use cases.

Robert Moskal
  • 21,737
  • 8
  • 62
  • 86
  • 2nd method look like great, i wanted to link database value ENUM to BEAN name automatic ^^ thanks – cyril Sep 12 '19 at 17:43
  • with this method i have a exception : org.jboss.weld.bean.ManagedBean cannot be cast to IGeneralService – cyril Sep 13 '19 at 15:04
  • My answer was in general and in broad strokes. You'll have to find out why your service is wrapped in that. – Robert Moskal Sep 13 '19 at 16:13
1

There is a far cleaner way to do it.

@interface Provider {
    String value(); // provider id retrieved from the db
}

class ProviderImpl extends AnnotationLiteral<Provider> implements Provider {
    String providerId;
    ProviderImpl(String providerId) { this.providerId = providerId;}
}

Then for each of your service provider, annotate them appropriately:

@Provider("provider-1")
class ProviderOneImpl implements ServiceProvider {}

Then the usage looks like this:

class ServiceProcessor {
   @Any
   @Inject
   Instance<ServiceProvider> serviceProviders;

   void doSomethingAwesome() {
      String enabledProvider = getCurrentProviderId();
      Provider provider = new ProviderImp(enabledProvider);
      ServiceProvider serviceProvider = serviceProviders.select(provider).get();
      serviceProvider.run();
   }
}
maress
  • 3,533
  • 1
  • 19
  • 37
0

thanks to all guys i finally implement this way :

How to programmatically inject a Java CDI managed bean into a local variable in a (static) method

it works

cyril
  • 872
  • 6
  • 29
  • like suggested as a duplicate? Then there is no need to create this as an answer but vote for it to be a duplicate too and post this as a comment ;-) – Kukeltje Nov 11 '19 at 11:40
0

You can inject de interface :

@Inject
@Any
private Instance <Payment> paymentsLazy;

after in your method you can choose the implementation

Payment object = paymentsLazy.select(Cash.class).get ();