Мне нравится изучать JAX -RS и Jersey, но я столкнулся с препятствием, пытаясь протестировать простой ресурс, который требует внедрения DAO, что-то вроде этого:
@Stateless
@Path("simple")
public class SimpleResource {
@PersistenceContext
private EntityManager em;
// @GET, etc...
}
(Я перейду к более абстрактному шаблону DAO, но проблема та же, т. е. как внедрить @EJB DAO?)
В своих модульных тестах я использую встроенный сервер Jetty, который настраивает Джерси в своем web.xml, и я хотел бы подключиться к жизненному циклу ресурса, чтобы я мог внедрить фиктивный EntityManager, но я не нашел четкого ответа после долгих поисков. Вы можете помочь? Некоторые возможные направления, с которыми я столкнулся:
1 )Используйте поиск контекста JNDI в моем коде, чтобы получить компонент DAO, и зарегистрировать фиктивный объект в тестах.
Вместо @EJB или @PersistenceContext используйте что-то подобное в конструкторе ресурса:
theDAO = (DAOImpl) new InitialContext().lookup("java:global/EJB/DAOImpl");
Однако это означает, что моя тестовая среда должна поддерживать JNDI, и выполнение этого в Jetty, вероятно, потребует некоторых усилий. Кроме того, он не использует метод чистой аннотации.
2 )Использовать метод впрыска.
Внедрить в метод, чтобы я мог установить экземпляр DAO post -, например,
@PersistenceContext(name = "persistence/pu00")
public void setPersistenceUnit00(final EntityManager em) {
em00 = em;
}
ИЛИ
private MyEjbInterface myEjb;
@EJB(mappedName="ejb/MyEjb")
public void setMyEjb(MyEjb myEjb) {
this.myEjb = myEjb;
}
Однако для этого мне нужен инстанцированный экземпляр Jersey -, например, SimpleResource. Как мне это получить?
3 )Используйте отражение.
Этакая самодельная инъекция, что-то вроде:
public static void setPrivateField(Class<? extends Object> instanceFieldClass, Object instance, String fieldName, Object fieldValue) {
Field setId = instanceFieldClass.getDeclaredField(fieldName);
setId.setAccessible(true);
setId.set(instance, fieldValue);
}
Опять же, мне нужен инстанцированный экземпляр Jersey -.
4 )Используйте поставщика инъекций.
Я все еще не понимаю, как это работает, но похоже, что Джерси предоставляет средства для определения настраиваемых инъекционных аннотаций, например,
@Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable getInjectable(ComponentContext cc, EJB ejb, Type t) {
if (!(t instanceof Class)) {
return null;
}
try {
Class c = (Class) t;
Context ic = new InitialContext();
final Object o = ic.lookup(c.getName());
return new Injectable<Object>() {
public Object getValue() {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
Вариант с использованием вспомогательного класса:
Server server = new Server(8080);
Context root = new Context(server,"/",Context.SESSIONS);
ResourceConfig rc = new PackagesResourceConfig("edu.mit.senseable.livesingapore.platform.restws.representations");
rc.getSingletons().add(new SingletonTypeInjectableProvider<javax.ws.rs.core.Context, Myobj>(Myobj.class, new Myobj(12,13)){});
root.addServlet(new ServletHolder(new ServletContainer(rc)), "/");
server.start();
При таком использовании:
@Path("/helloworld")
public class HelloWorldResource {
@Context Myobj myClass;
....
}
Это жизнеспособно для @EJB или @PersistenceContext?
5 )Расширить javax.ws.rs.core.Application.
Схематично об этом, но:
@javax.ws.rs.ApplicationPath("application")
public class InjectionApplication extends javax.ws.rs.core.Application {
private Set<Object> singletons = new HashSet<Object>();
private Set<Class<?>> classes = new HashSet<Class<?>>();
public InjectionApplication() {
// no instance is created, just class is listed
classes.add(BookResource.class);
}
@Override
public Set<Class<?>> getClasses() {
return classes;
}
@Override
public Set<Object> getSingletons() {
return singletons;
}
}
6 )Расширение контейнера сервлетов.
Старый стиль использования InjectableProvider? Выглядит сложнее:
public class ServletAdapter extends ServletContainer {
@Override
protected void configure(ServletConfig servletConfig, ResourceConfig rc, WebApplication wa) {
super.configure(servletConfig, rc, wa);
rc.getSingletons().add(new InjectableProvider<Resource, Type>() {
public ComponentScope getScope() {
return ComponentScope.Singleton;
}
public Injectable<Object> getInjectable(ComponentContext ic, Resource r, Type c) {
final Holder value = new Holder();
Context ctx = new InitialContext();
try {
value.value = ctx.lookup(r.name());
} catch (NamingException ex) {
value.value = ctx.lookup("java:comp/env/" + r.name());
}
return new Injectable<Object>() {
public Object getValue() {
return value.value;
}
};
}
});
}
}
7 )Используйте встроенный контейнер EJB.
Например,http://openejb.apache.org. Это довольно тяжело, и я ожидаю, что это будет грязно, чтобы работать. (На самом деле, то, что заставило меня пойти по маршруту «Jetty + Jersey», было ошибкой в GlassFish Embedded, связанной с безопасностью входа в систему. Я также рассмотрел другие контейнеры приложений Java EE 6, такие как JBoss AS, но у каждого из них были проблемы во встроенном режиме с ограниченной поддержкой сообщества пользователей.)
8 )Используйте стороннюю -библиотеку IoC, такую как Spring или Guice.
Spring, по-видимому, обычно используется для решения таких проблем (внедрение макетов при модульном тестировании ), но я хотел избежать изучения другого большого набора API -чистая Java EE была достаточно сложной задачей! Но я в игре, если это лучшее решение. Я еще не внимательно изучил Spring или Guice.
Вы успешно использовали что-то из этого? Любые другие решения, которые вам нравятся? Очень жду ваших советов по этому поводу. Заранее спасибо --матовый