2013-05-02 3 views
0

У меня есть проект Maven с этой структурой:@EJB аннотаций не работает для инициализации бина в приложении EJB

-myproject 
    -myproject-ear 
    -myproject-service 
    -webservice 
    -myproject-ejb 

В myproject-ejb у меня есть это Java пакеты:

-src/main/java/ 
-src/test/java/ 

у меня есть EJB и соответствующая реализация компонента в

-src/main/java/org/mypackage/MyBean.java 
-src/main/java/org/mypackage/MyBeanImpl.java 

В src/test/java/ У меня есть тест под названием MyBeanTest.java со следующим кодом:

import javax.ejb.EJB; 
import org.mypackage.MyBean; 
import org.junit.*; 

public class MyBeanTest { 

    @EJB 
    private MyBean myBean; 

    @Test 
    public void testBean() { 
     System.out.println("myBean: "+myBean); // prints null 
     myBean.writeToDB("Hello", "World"); // fails since myBean is null 
    } 
} 

При запуске теста на единицу, то myBean равно нулю. Мне интересно, почему аннотация @EJB не работает. Пакет для тестирования находится в том же приложении, что и компонент, поэтому @EJB должен работать.

Любые идеи?

EDIT 1
Я нашел this link с той же проблемой, как у меня есть, но решение там, кажется, это не распространяется на работу для меня. Я что-то делаю неправильно?

package org.myproject.ejb; 

import java.util.Hashtable; 
import java.util.Properties; 

import javax.ejb.EJB; 
import javax.naming.Context; 
import javax.naming.InitialContext; 
import javax.naming.NamingException; 
import javax.servlet.ServletException; 

import org.myproject.ejb.MyBean; 
import org.jboss.ejb.client.ContextSelector; 
import org.jboss.ejb.client.EJBClientConfiguration; 
import org.jboss.ejb.client.EJBClientContext; 
import org.jboss.ejb.client.PropertiesBasedEJBClientConfiguration; 
import org.jboss.ejb.client.remoting.ConfigBasedEJBClientContextSelector; 
import org.junit.*; 

public class MyBeanTest { 

    private MyBean myBean; 

    @Before 
    public void init() { 
     try { 
      Properties clientProp = new Properties(); 
      clientProp.put("remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED", "false"); 
      clientProp.put("remote.connections", "default"); 
      clientProp.put("remote.connection.default.port", "4447"); 
      clientProp.put("remote.connection.default.host", "localhost"); 
      clientProp.put("remote.connection.default.connect.options.org.xnio.Options.SASL_POLICY_NOANONYMOUS", "false"); 


      EJBClientConfiguration cc = new PropertiesBasedEJBClientConfiguration(clientProp); 
      ContextSelector<EJBClientContext> selector = new ConfigBasedEJBClientContextSelector(cc); 
      EJBClientContext.setSelector(selector); 

      Properties env = new Properties(); 
      env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming"); 
      env.put(Context.SECURITY_PRINCIPAL, "admin"); 
      env.put(Context.SECURITY_CREDENTIALS, "testing"); 
      InitialContext ctx = new InitialContext(env); 
      myBean = (MyBean) ctx.lookup("java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl"); 
     } 
     catch(NamingException ex) { 
      ex.printStackTrace(); 
     } 
    } 

    @Test 
    public void testBean() { 
     System.out.println("ejb: "+myBean); // prints null 
    } 
} 

Я получаю ошибку с помощью данной конфигурации:

WARN: Unsupported message received with header 0xffffffff 
javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial 
    at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:662) 
    at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:307) 
    at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:344) 
+1

Я считаю, что аннотация @EJB будет работать только в классах, управляемых контейнером сервлетов (например: сервлеты, управляемые компоненты, EJB и т. Д.). Если что-то не изменилось в последнее время, я бы не ожидал, что он будет работать в случайном классе pojo. – jahroy

+0

Вы посмотрели http://www.junitee.org/? –

+1

Вот [ответ] (http://stackoverflow.com/a/850006/778118), что также говорит о том, что @EJB работает только с управляемыми классами ... – jahroy

ответ

4
  1. Контейнер инъекция ресурсов, такие как @EJB, требует населенного каталога JNDI и работает только в Java EE управляемого компонентов выполняющихся в контейнере Java EE. Это вызов для модульного тестирования. См. JSR318 Java EE 6 Platform Spec, раздел EE.5 «Ресурсы», «Именование и инжекция».

  2. Теперь вы пытаетесь выполнить поиск JNDI - тестовое приложение Java SE, удаленно подключающее его контекст JNDI. Недостатки: необходимо развернуть полное приложение Java EE 6 в качестве предварительного условия для запуска теста; test-bugfix-build-deploy-retest жизненный цикл может замедлить работу.

    Некоторые вопросы:

    • своё имя пользователя/пароль, свойства различны чем JBoss документ;
    • От док он отображается имя JNDI поиска должно быть "ejb:...", а не "java:app/...", так как код EJB-клиент-проект JBoss использует это, чтобы перехватить поиск. Также из спецификации платформы Java EE 6 spec EE.5.2.2: Имена в java:app пространства имен разделяются всеми компонентами всех модулей в одном приложении Java EE. Если ваш тест является отдельным JSE-приложением, использующим java:app, я подозреваю, что JBoss рассматривает его как отдельный для одного приложения Java EE, и поиск не удастся.
    • Убедитесь, что вы LookUp интерфейс, а не класс реализации (то есть EJB не вид интерфейса) для удаленного доступа
    • Вы отсылая к необычному ссылки, показывая прямое использование EJBClientConfiguration & EJBClientContext. Кажется, это не требуется/не рекомендуется.

    Try эти действия:

    • Включите эти свойства:

      clientProp.put("remote.connection.default.username", "admin"); 
      clientProp.put("remote.connection.default.password", "testing"); 
      
    • Изменить клиента ссылка:

      java:app/myproject-ejb-1.0-SNAPSHOT/MyBeanImpl to 
      
      ejb:<app-ear-name>/<module-jar-name>/<jboss-optional-distinct-name>/<bean-name>!<fully-qualified-classname-of-the-remote-interface> 
      

      E.g. если MyBean - это EJB без гражданства, развернутый в myproject-ejb-1.0-SNAPSHOT.jar (без ушей). Затем:

      ejb:/myproject-ejb-1.0-SNAPSHOT//MyBeanImpl!org.mypackage.MyBean 
      

      Если это состояние EJB с состоянием, добавьте строку «? Stateful» в строку.

    • Установка ejb-client.properties напрямую (с помощью файла или программы) и применимость непосредственно к JNDI Context. См https://docs.jboss.org/author/display/AS72/EJB+invocations+from+a+remote+client+using+JNDI и https://docs.jboss.org/author/display/AS72/Scoped+EJB+client+contexts и http://middlewaremagic.com/jboss/?p=1177

  3. В будущем: использовать CDI для инъекций; JUnit + CDI @Mock для модульного тестирования «POJO»; Arquillian для тестирования модулей/модулей Java EE в контейнерах. Затем вы можете избежать/уменьшить тесты, такие как (2) выше (JSE client -> EJB). CDI поддерживает:

    • Java EE инъекции ресурсов в POJOs (включая @EJB аннотацию). Это по-прежнему требует развертывания Java EE app/component и заполненного каталога JNDI для поиска.
    • Управляемые компоненты в виде POJO или компонентов Java EE (включая EJB) - вводят «любые» в «любые» с помощью превосходной аннотации @Inject. Работает без каталога JNDI, является типом & bean scope-aware.

    • Поддерживает модульное тестирование посредством простого издевательств. Используйте @Mock & @Specializes, чтобы объявить замену для любого компонента. Проверьте клиентов EJB без EJB. Проверьте EJB как POJO.

    Чтобы включить CDI, включают в себя beans.xml файл (может быть пустым, если все конфигурации с помощью аннотаций).

    Чтобы объявить управляемый компонент:

    • дополнительный объем выше класса, например, @SessionScoped
    • конструктор без аргументов/@Inject на конструктор

    Используйте это, чтобы ввести ссылку:

    @Inject (optional @MyDeclaredQualifier) private MyBean myBean; 
    

    Arquillian ("JUnit для Java EE 6") запускает сам тестовый код на Java EE сервер. Он динамически развертывает тестовый код до сконфигурированного container(s) и запускает тесты. Он поддерживает аннотацию @EJB, соединение JNDI становится простым, и вы можете включать классы Java EE в модульные тесты без издевательств или рефакторинг, чтобы абстрагироваться от них.

+0

Спасибо за очень четкий ответ! Я понятия не имел, что я должен использовать 'ejb: / ...'. Это решило мою проблему. Благодаря! – Rox

2

1) инъекции аннотаций осуществляется контейнером. Таким образом, класс, который не управляется (управляемый контейнером), не сможет выполнить аннотацию.

2) Теперь, в этом сценарии, вы должны сделать ручной вызов JNDI и получить EJB экземпляра:

т.е.:

InitialContext ctx = new InitialContext();  
MyBean bean = (MyBeanRemote) ctx.lookup("java:global/<portable jndi name of your bean>"); 

Примечание : Использование конструктора arg arg InitialContext(). Потому что ваш класс Java развернут на сервере, который я предполагаю. Или вам может потребоваться указать фабричный класс контекста, если ваш класс является автономным java-классом, в зависимости от поставщика.

Примечание: Вам потребуется Bean Remote интерфейс, если вы делаете вызов EJB из другого приложения (то есть: разные войны, ухо ...) или же Местный интерфейс достаточно.

+0

Спасибо, что постарались мне помочь. Я уже тестировал метод 'lookup' без каких-либо успехов. Пожалуйста, посмотрите мои изменения в моем первоначальном сообщении. У моего компонента есть интерфейс «Удаленный». – Rox

+0

@Rox, каково отображаемое имя jndi компонента ejb? –

+0

«Ваш класс Java развернут на сервере, который я предполагаю» - он запускает JUnit. Я не думаю, что он работает на сервере. Вот почему у него есть сложные, специфичные для вендора свойства, используемые для построения InitialContext с удаленным доступом. –

1

Это исключение вызывается, когда не может быть создана начальная реализация контекста. Политика выбора начальной реализации контекста описана в документации по классу InitialContext.

Это исключение может быть выбрано во время любого взаимодействия с InitialContext, а не только при построении InitialContext.Например, реализация исходного контекста может лениво извлекать контекст только тогда, когда на него вызывают действительные методы. Приложение не должно иметь никакой зависимости от того, когда будет определено существование начального контекста.

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