Следующий скимпсет кода работает с «weld-core-1.1.5.AS71.Final.jar» (тот, который используется JBoss 7.1.1), но не работает с «weld-core-impl-2.2.6.Final.jar» (тот, который используется wildfly 8.2).Резолюция типа CDI не работает в сварном шве 2.2.6, когда параметр типа bean-типа является переменной типа
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;
}
}
Почему? CDI 1.2 Спецификация:
параметризованный тип фасоли считается присваиваемым параметризованным требуемого типа, если они имеют одинаковый сырой тип и для каждого параметра:
- требуемого параметра типа и параметра типа фасоли являются действительными типами с идентичным сырым типом, и, если тип параметрирован, параметр типа bean-типа присваивается параметру требуемого типа в соответствии с этими правилами или
- требуемый тип paramete r является подстановочным знаком, параметр типа bean-типа является фактическим типом, и фактический тип присваивается верхнему связанным, если таковые имеются, подстановочным знаком и присваиваемым из нижней границы, если любой, подстановочного знака, или
- параметр требуемого типа является подстановочным знаком, параметр типа bean - это переменная типа, а верхняя граница переменной типа - , назначаемая или назначаемая из верхней границы, если таковая имеется, из подстановочного знака и назначается из нижней границы, если любой из подстановочного знака или
- параметр требуемого типа является фактическим типом, параметр типа bean - это переменная типа, а фактический тип присваивается верхней границе, если таковая имеется, типа varia или
- параметр требуемого типа и параметр типа bean - это переменные типа, а верхняя граница требуемого параметра типа - , назначаемая верхней границе, если таковая имеется, параметра типа bean.
Так, согласно пункту # 4, приведенный выше код должен работать, не так ли?
Edit 1: < - См Отредактируйте 2 раньше. Там я заметил, что реализация CDI делает то, что я ожидал от этого, но я ошибочно считал, что это не так.
Ответ Антонина Стефанутти прав: пункт № 4 указанной спецификации не применяется. Но, если фактический тип переменной типа T известен, когда точка inyectión разрешена, можно получить правильный экземпляр Spi
.
Supouse Client
класс абстрактный, а реализация определяет тип параметра типа в определении класса. В этом случае фактический тип может быть обнаружен, и будет применен элемент № 4 спецификации.
Как можно решить? С помощью интроспекции, используя операцию Class#getGenericInterfaces()
, на фактическом Class
экземпляра Client
.Как это:
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> {}
}
Приведенный выше код работает (экземпляр SpiImpl_1
вводится в spi
переменную экземпляра), поэтому, почему бы не могли КДИ сделать эту работу для нас? С помощью instrospection можно обнаружить фактический тип каждого параметра типа, объявленного в определении класса/интерфейса, когда конкретный класс указывает фактический тип параметра расширенного суперкласса.
Редактировать 2 Извините, забудьте все, что я сказал. В этом втором примере CDI вводит соответствующий пример Client
без необходимости добавления программной инициализации. Он не бросает «WELD-001408: неудовлетворенные зависимости для типа Spi», где я сказал, что это так. Я был неправ. Еще раз извините. Должен ли я удалить этот вопрос?