The following code snipset works with "weld-core-1.1.5.AS71.Final.jar" (the one used by JBoss 7.1.1), but doesn't work with "weld-core-impl-2.2.6.Final.jar" (the one used by wildfly 8.2).
public class Client<T> {
public interface Spi<T> {
T getSomething();
}
@Inject
private Spi<T> spi; // WELD-001408: Unsatisfied dependencies for type Spi<Object>
}
public class SpiImpl implements Client.Spi<Integer> {
@Override
public Integer getSomething() {
return 5;
}
}
Why? The CDI 1.2 specification:
A parameterized bean type is considered assignable to a parameterized required type if they have identical raw type and for each parameter:
- the required type parameter and the bean type parameter are actual types with identical raw type, and, if the type is parameterized, the bean type parameter is assignable to the required type parameter according to these rules, or
- the required type parameter is a wildcard, the bean type parameter is an actual type and the actual type is assignable to the upper bound, if any, of the wildcard and assignable from the lower bound, if any, of the wildcard, or
- the required type parameter is a wildcard, the bean type parameter is a type variable and the upper bound of the type variable is assignable to or assignable from the upper bound, if any, of the wildcard and assignable from the lower bound, if any, of the wildcard, or
- the required type parameter is an actual type, the bean type parameter is a type variable and the actual type is assignable to the upper bound, if any, of the type variable, or
- the required type parameter and the bean type parameter are both type variables and the upper bound of the required type parameter is assignable to the upper bound, if any, of the bean type parameter.
So, according to item #4, the above code should work, shouldn't it?
Edit 1: <-- See Edit 2 before. There I noticed that the CDI implementation is doing what I expected it should do, but I mistakenly thought it didn't.
Antonin Stefanutti answer is right: item #4 of the mentioned specification don't apply. But, if the actual type of the type variable T is known when the inyectión point is resolved, it is possible to get a proper instance of Spi
.
Supouse Client
class is abstract and an implementation specifies the type of the type parameter in the class definition. In that case, the actual type can be discovered and item #4 of the specification would apply.
How can be resolved? By means of introspection, using Class#getGenericInterfaces()
operation, on the actual Class
of the Client
instance. Like this:
public class Test {
@Inject
private ClientImpl clientImpl;
public abstract static class Client<T> {
public interface Spi<T> {
T getSomething();
}
// @Inject inject don't work because CDI doesn't require it even when the actual type of T can be discovered. So, instead, I initialized it programaticaly in the postConstruct()
private Spi<T> spi; // WELD-001408: Unsatisfied dependencies for type Spi<Object> // Not true, later, in "edit 2" I noteced it works fine. Forget all this. Sorry.
@Inject
private Instance<Spi<?>> spiFinder;
/**Initializes the spi instance variable programaticaly */
@PostConstruct
private void postConstruct(){
ParameterizedType clientType = (ParameterizedType)this.getClass().getGenericSuperclass();
Type clientTypeParamter = clientType.getActualTypeArguments()[0];
Class<T> clientParameterClass = (Class<T>)clientTypeParamter;
final Iterator<Spi<?>> iterator = spiFinder.iterator();
while (iterator.hasNext()) {
Spi<?> spiCandidate = iterator.next();
ParameterizedType spiCandidateType = (ParameterizedType)spiCandidate.getClass().getGenericInterfaces()[0];
Type spiCandidateTypeParameter = spiCandidateType.getActualTypeArguments()[0];
Class<?> spiCandidateParameterClass = (Class<?>)spiCandidateTypeParameter;
if( clientParameterClass.isAssignableFrom(spiCandidateParameterClass)) {
if( spi != null)
throw new AmbiguousResolutionException();
spi = (Spi<T>)spiCandidate;
}
}
if( spi == null)
throw new UnsatisfiedResolutionException();
}
}
@Dependent
public static class SpiImpl_1 implements Client.Spi<Integer> {
@Override
public Integer getSomething() {
return 5;
}
}
@Dependent
public static class SpiImpl_2 implements Client.Spi<Double> {
@Override
public Double getSomething() {
return 5.0;
}
}
@Dependent
public static class ClientImpl extends Client<Integer> {}
}
The above code works (an instance of SpiImpl_1
is injected into spi
instance variable), so, why couldn't CDI do this job for us? With instrospection it's possible to discover the actual type of every type parameter declared in the enclosing class/interface definition when the concrete class specifies the actual type of extended superclass's type parameter.
Edit 2
Sorry, forget everything I have said. CDI does inject the proper instance of Client
in this second example without the need of the programatic initialization I added. It doen't throw "WELD-001408: Unsatisfied dependencies for type Spi" where I said it does. I was wrong. Sorry again.
Should I delete this question?