2015-10-13 6 views
2

Я занимаюсь реорганизацией старого модуля, добавив CDI.Внутренняя зависимость не вводится (Weld + JavaSE)

Я заканчиваю с

public interface ApiFactory { 
    ... 
} 

public class ApiFactorySp 
    implements ApiFactory { 
    @Inject 
    UrlProducer urlProducer; // <-- Does not get injected 
    ... 
} 

и

public interface UrlProducer { 
    public String getUrl(); 
} 

@Alternative 
public class UrlProducerTest 
    implements UrlProducer { 

    @Override 
    public String getUrl() { 
     return "https://myTestEnv.mydomain/myWebApp"; 
    } 
} 

Для тестирования, я создаю beans.xml файл в META-INF:

<beans 
    xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
    http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd" 
    bean-discovery-mode="all"> 
    <alternatives> 
     <class>myOrg.myProject.myPackage.UrlProducerTest</class> 
    </alternatives> 
</beans> 

Чтобы проверить это, я делаю, как показано in this blog

public class WeldContext { 

    public static final WeldContext INSTANCE = new WeldContext(); 

    private final Weld weld; 
    private final WeldContainer container; 

    private WeldContext() { 
     this.weld = new Weld(); 
     this.container = weld.initialize(); 
     Runtime.getRuntime().addShutdownHook(new Thread() { 

      @Override 
      public void run() { 
       weld.shutdown(); 
      } 
     }); 
    } 

    public <T> T getBean(Class<T> type) { 
     return container.instance().select(type).get(); 
    } 
} 

и

public class WeldJUnit4Runner extends BlockJUnit4ClassRunner { 

    public WeldJUnit4Runner(Class<Object> clazz) throws InitializationError { 
     super(clazz); 
    } 

    @Override 
    protected Object createTest() { 
     final Class<?> test = getTestClass().getJavaClass(); 
     return WeldContext.INSTANCE.getBean(test); 
    } 
} 

Теперь, когда я пытаюсь проверить логику, я

@RunWith(WeldJUnit4Runner.class) 
public class MyTest { 
    @Inject 
    UrlProducer urlProducer;   

    @Inject 
    ApiFactory apiFactory; 

    @Test 
    public void test() { 
     apiFactory.doSomethingThatRequiresUrlProducer(); 
    } 
} 

Когда я запускаю это, оба тестируемых атрибутов инъекционные, но я получаю NPE, потому что атрибуту urlProducer внутри экземпляра apiFactory не присвоено значение.

Почему Weld не распознает атрибут @Inject внутри ApiFactory?

JDK 7, Weld 2.2.10 Junit 4,12

UPDATE: После размещения вопроса, начал пробовать с более простым, новым проектом (только с двумя интерфейсами и три классов). Использование Weld «standalone» не решило проблему, используя CDI-Unit.

Затем я изменил свой первоначальный проект на использование CDI-Unit, но ничего не улучшил. После этого меняю инъекцию UrlProducerTest в ApiFactory из поля в конструктор (т. Е. Определяя конструктор @Inject ApiFactory(UrlProducer urlProducer)). Я до сих пор не пробовал это решение с «автономным» Weld (то есть на завтра), но тем не менее меня все еще интересует, почему полевая инъекция не работает.

+0

Вы уверены, что NPE не потому, что apiFactory не вводится? –

+0

@ A.Panzer Да, я уверен, что «apiFactory» вводится. Но поскольку я собирался ответить, я думал, что я был уверен, потому что код, который использует 'UrlProducer', является ** в конструкторе **: - *>, и это вызывает исключение, которое должно быть выбрано во время создания экземпляра ... У меня будет чтобы проверить это завтра, но, возможно, вы хотите переписать свой ответ, чтобы принять это во внимание. – SJuan76

ответ

1

Если UrlProducerTest является альтернативой, и вы хотите ввести этот компонент, этот класс должен быть добавлен в beans.xml в тег <alternatives>.

EDIT:

Я считаю, что если какой-то компонент не может быть введен вы получите исключение с сообщением "Неудовлетворенные/неоднозначных зависимостями. Null может быть введено, если вы использовали метод CDI producer, который вернул значение null, но это не ваш сценарий.

Так что, если нет ошибок в консоли у меня есть два предположения:

  1. Injection не работает на всех, и вы получите NPE, потому что apiFactory является нулевым

  2. используется urlProducer перед инъекцией. Например, из блока конструктора или инициализации (apiFactory.doSomethingThatRequiresUrlProducer() не предоставляется). Поэтому переместите эту логику на какой-то метод и аннотируйте ее с помощью @PostConstruct

+0

Хорошо распознанный, к сожалению, «UrlProducerTest» объявлен как альтернатива (я изменил имена классов для более простых версий в коде, но оставил его немодифицированным в файле 'beans.xml',' UrlSharepointTest', который появился в предыдущем выпуске был фактически «UrlProducerTest». – SJuan76

+0

Действительно, я пропустил то, что использовал этот атрибут у конструктора (как я уже сказал, я рефакторинг какого-то кода, отличного от CDI). Очевидно, что после ввода поля происходит ** после ** bean был создан (то есть, после завершения команды 'new'), я не мог использовать значения полей внутри конструктора. Переместил логику в метод' @ PostConstruct'. – SJuan76

0

Потому что ApiFactorySp не является компонентом CDI. Вам необходимо аннотировать класс с помощью @Named, чтобы идентифицировать класс как компонент CDI для CDI для выполнения инъекции зависимостей.

+0

Спасибо, но вы ошибаетесь. Бинзы CDI не требуют аннотации; '@ Named' может использоваться для создания бина, доступного через EL, но не требуется для прямого впрыска: http://docs.oracle.com/javaee/6/tutorial/doc/gjfzi.html. Кроме того, из текста моего вопроса ясно, что бобы обнаруживаются как таковые Weld, поскольку они вводятся в моем тестовом экземпляре. – SJuan76

Смежные вопросы