LppEdd
LppEdd

Reputation: 21114

CDI conditional Bean with Instance<T>

I have the necessity to provide the correct Bean implementation at runtime.

The common interface:

public interface MyInterface { ... }

The implementations:

@Named("one")
class MyInterfaceImpl1 implements MyInterface { ... }

@Named("two")
class MyInterfaceImpl2 implements MyInterface { ... }

@Named("three")
class MyInterfaceImpl3 implements MyInterface { ... }

Notice these classes are package-private.

I then wrote a @Produces method:

@Produces
@Singleton
MyInterface getMyInterface(
        final Instance<MyInterface> myInterfaceImplementations,
        final Configuration configuration) {
    // Might be one, two or three.
    final String parameter = configuration.getString("value");
    return myInterfaceImplementations.select(new NamedLiteral(parameter)).get();
}

Is this the correct way to go, or is there a better solution?

Upvotes: 4

Views: 762

Answers (2)

Siliarus
Siliarus

Reputation: 6753

Your solution would work fine, here are my 0.02$ just to make sure you intended it that way:

What Nikos Paraskevopoulos meant in his comment is that your are effectively creating four beans to inject one. MyInterfaceImpl1, MyInterfaceImpl2, MyInterfaceImpl3 are all legitimate beans for injection anywhere in the app. If these beans are heavy, creation may take some time, also the ability to inject them anywhere might not be intended? And then there is your producer method - the fourth bean - which I assume is ultimately the only one you are after.

Secondly, the three implementation beans have different scope from the producer method. If they are eligible for injection, in your case it seems logical that they share same scope perhaps?

Thirdly, using @Singleton. I would also advice for @ApplicationScoped, there is no harm and no overhead by having a proxy. You won't be able to tell the difference and can easily avoid some unpleasant surprises with CDI singleton (which doesn't behave like EJB singleton).

Upvotes: 1

TacheDeChoco
TacheDeChoco

Reputation: 3903

I think a more elegant solution would be to let the CDI do all the magic ;-) Something like:

import javax.enterprise.inject.spi.CDI;

@Produces
@Singleton
MyInterface getMyInterface(final Configuration configuration) {
    // Might be one, two or three.
    final String parameter = configuration.getString("value");
    Set<MyInterface> candidates = CDI.current().getBeanManager().getBeans(parameter);
    return ( candidates.size()>0 ? candidates.get(0) : null);
}

You could also use the alternate signature of getBeans() signature to play with qualifiers when looking for a particular impl of your interface: cfr https://docs.oracle.com/javaee/7/api/javax/enterprise/inject/spi/BeanManager.html#getBeans-java.lang.reflect.Type-java.lang.annotation.Annotation...-

Upvotes: 0

Related Questions