I'm trying to use a POJO as CDI producer for injecting the right EJB but I get org.jboss.weld.exceptions.UnsatisfiedResolutionException: WELD-001308.
This is my producer POJO
public class STGatewayUtilProducer {
@Produces
@Chosen
public ISTGatewayUtil getISTGatewayUtil(Instance<STGatewayWSUtil> ws, Instance<STGatewayMQTTUtil> mqtt, ConfigurationManager cm) {
switch(cm.getGatewayProtocol()) {
case ConfigurationManager.GATEWAY_PROTOCOL_TYPE_MQTT:
return mqtt.get();
default:
return ws.get();
}
}
}
This is the qualifier definition:
@Qualifier
@Target({ TYPE, METHOD, PARAMETER, FIELD })
@Retention(RUNTIME)
@Documented
public @interface Chosen {}
And those are the EJB declarations:
@Stateless
public class STGatewayMQTTUtil implements Serializable, ISTGatewayUtil {
...
}
@Stateless
public class STGatewayWSUtil implements Serializable, ISTGatewayUtil {
...
}
Finally, this is the way I'm injecting the EJB:
@Inject
@Chosen
private Instance<ISTGatewayUtil> gtwUtil;
I'm facing the problem both with JBoss AS 7 and WildFly 10.
I found the core of my problem! I declared a common abstract
parent class which implements the ejb interface and let my session beans extend it: using this structure the beans can't be resolved.
Instead, if i move the implements
clause on session beans the problem disappear: may someone explain me what's wrong with my class hierarchy?
Quoting the specification
3.2.2. Bean types of a session bean
The unrestricted set of bean types for a session bean contains all local interfaces of the bean and their superinterfaces. If the session bean has a no-interface view, the unrestricted set of bean types contains the bean class and all superclasses. In addition, java.lang.Object is a bean type of every session bean.
Remote interfaces are not included in the set of bean types.
So here as both of your session bean have a local interface, they don't have their classes in their set of bean types. Thus it is normal that you can't resolve them with their class.
You need to add extra info to your session beans definition to be able to distinguish them or declare them as No-Interface view EJB with @LocalBean annotation.
Here's a new version of your code declaring your EJB as NIV
@Stateless
@LocalBean
public class STGatewayMQTTUtil implements Serializable, ISTGatewayUtil {
...
}
@Stateless
@LocalBean
public class STGatewayWSUtil implements Serializable, ISTGatewayUtil {
...
}
Your producer don't need to inject 2 Instances<T>
. You can either inject both beans and return the chosen one.
public class STGatewayUtilProducer {
@Produces
@Chosen
public ISTGatewayUtil getISTGatewayUtil(STGatewayWSUtil ws, STGatewayMQTTUtil mqtt, ConfigurationManager cm) {
switch(cm.getGatewayProtocol()) {
case ConfigurationManager.GATEWAY_PROTOCOL_TYPE_MQTT:
return mqtt;
default:
return ws;
}
}
}
or use Instance<T>
like this
public class STGatewayUtilProducer {
@Produces
@Chosen
public ISTGatewayUtil getISTGatewayUtil(Instance<ISTGatewayUtil> gw, ConfigurationManager cm) {
switch(cm.getGatewayProtocol()) {
case ConfigurationManager.GATEWAY_PROTOCOL_TYPE_MQTT:
return gw.select(STGatewayMQTTUtil.class).get();
default:
return gw.select(STGatewayWSUtil.class).get();
}
}
}
Be careful when you use a bean instance to produce a new bean, it should have the @Dependent
scope (to avoid superposing 2 lifecycle on your produced bean) or be injected with @New
keyword. Here your session beans are in @Dependent
scope since they don't specify any scope.