2015-04-23 1 views
0

Следующий скимпсет кода работает с «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 Спецификация:

параметризованный тип фасоли считается присваиваемым параметризованным требуемого типа, если они имеют одинаковый сырой тип и для каждого параметра:

  1. требуемого параметра типа и параметра типа фасоли являются действительными типами с идентичным сырым типом, и, если тип параметрирован, параметр типа bean-типа присваивается параметру требуемого типа в соответствии с этими правилами или
  2. требуемый тип paramete r является подстановочным знаком, параметр типа bean-типа является фактическим типом, и фактический тип присваивается верхнему связанным, если таковые имеются, подстановочным знаком и присваиваемым из нижней границы, если любой, подстановочного знака, или
  3. параметр требуемого типа является подстановочным знаком, параметр типа bean - это переменная типа, а верхняя граница переменной типа - , назначаемая или назначаемая из верхней границы, если таковая имеется, из подстановочного знака и назначается из нижней границы, если любой из подстановочного знака или
  4. параметр требуемого типа является фактическим типом, параметр типа bean - это переменная типа, а фактический тип присваивается верхней границе, если таковая имеется, типа varia или
  5. параметр требуемого типа и параметр типа 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», где я сказал, что это так. Я был неправ. Еще раз извините. Должен ли я удалить этот вопрос?

ответ

1

В вашем примере параметр нулевого типа является переменной типа, T, а не фактическим типом, так что элемент № 4 не применяется. На самом деле, любое из условий, упомянутых в спецификации для присваивания параметризованного типа bean к параметризованному требуемому типу, выполняется в вашем примере, что убедительно означает, что зависимость не выполняется.

Это как-то связано с CDI-517, хотя и не идентичным, но пояснение может объяснить поведенческие изменения между Weld 1.x и Weld 2.x по мере уточнения спецификации.

Как уже упоминалось в этой дискуссии, имея Spi<Integer>назначаемые к Spi<T> было бы неправильно с точки зрения языка сайта Java.