How and who should inject PersistenceContext when running tests through Jersey/Grizzly? - java

I have this class (mix of JAX-RS/Jersey and JPA/Hibernate):
public class Factory {
#PersistenceContext(unitName = "abc")
EntityManager em;
#Path("/{id}")
#GET
public String read(#PathParam("id") int i) {
return em.find(Employee.class, i).getName();
}
}
This is the unit test:
public class FactoryTest extends JerseyTest {
public FactoryTest() throws Exception {
super("com.XXX");
}
#Test
public void testReadingWorks() {
String name = resource().path("/1").get(String.class);
assert(name.length() > 0);
}
}
Everything is fine here except one this: em is NULL inside read(). Looks like Grizzly (I'm using this server together with Jersey Test Framework) is not injecting PersistenceContext. What am I doing wrong here?

Everything is fine here except one this: em is NULL inside read(). Looks like Grizzly (I'm using this server together with Jersey Test Framework) is not injecting PersistenceContext. What am I doing wrong here?
I'm not sure Grizzly offers injection.
I'm not sure injection is supported in "any" Jersey resource anyway (Paul Sandoz seems to imply it should be in this thread but I couldn't find clear evidence of that claim).
So to my knowledge, the easiest solution would be to inject the EntityManager into an EJB 3.1 Stateless Session Bean (SLSB) which can be exposed directly as a REST resources (by annotating it with JAX-RS annotations).
Another option would make the JAX-RS resource a managed bean and to use CDI for injection. That's the approach of the TOTD #124: Using CDI + JPA with JAX-RS and JAX-WS.
In both cases, I think you'll need to use the Embedded GlassFish container as container for your Jersey Tests.
Resources
Jersey Test Framework makes it easy!
Jersey Test Framework re-visited!
RESTFul Calculator With JavaScript And ...EJB 3.1
TOTD #124: Using CDI + JPA with JAX-RS and JAX-WS

I found a solution for com.sun.jersey/jersey-grizzly2 version 1.x. I implemented a custom InjectableProvider. The following code is taken from an Oracle article:
import javax.ejb.EJB;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.ws.rs.ext.Provider;
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.core.spi.component.ComponentScope;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.InjectableProvider;
#Provider
public class EJBProvider implements InjectableProvider<EJB, Type> {
public Scope getScope() {
return Scope.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(HttpContext c) {
return o;
}
};
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
I had to slightly adapt it to fit my environment. Also note that the provider has to be in the same package as your service class, otherwise it won't be picked up (it does not say that in the article).

Related

Providing the SecurityIdentity directly to a Quarkus/RESTEasy web service method

I am using Quarkus with RESTEasy to make a web service and I need access to the SecurityIdentity in some of my methods.
It is possible to get it injected by making the service RequestScoped:
#RequestScoped
#Path("/foo")
public class FooResource {
#Inject
public SecurityIdentity securityIdentity;
#GET
public Foos getFoos() {
// use securityIdentity
}
}
But I would prefer to have the class ApplicationScoped and have the SecurityIdentity provided to the method instead. Something like this:
#ApplicationScoped
#Path("/foo")
public class FooResource {
#GET
// This does not work, Quarkus tries to convert the request body to a SecurityIdentity.
public Foos getFoos(SecurityIdentity securityIdentity) {
// use securityIdentity
}
}
Is this possible? Is there a magic annotation I can put on to make Quarkus inject the SecurityIdentity?
Keeping it injected into a field will still work for ApplicationScoped beans and be thread safe

Error on creating custom log4j Appender

I'm trying to create a custom Appender that will persist logs to the database using JPA.
The thing is that I'm using PersistenceContext attribute like this
package com.foobar.logging;
import com.foobar.model.SysLog;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.MDC;
import org.apache.log4j.spi.LoggingEvent;
import javax.ejb.Stateless;
#Stateless
public class LogManager extends AppenderSkeleton {
#PersistenceContext(unitName = "primary")
private EntityManager em;
#Override
protected void append(LoggingEvent le) {
SysLog log = new SysLog();
log.setDescripcion(le.getMessage().toString());
if (MDC.get("IdUsuario") != null) {
log.setIdUsuario(MDC.get("IdUsuario").toString());
}
log.setSysAccionLog(null);
this.em.persist(log);
}
#Override
public void close() {
}
#Override
public boolean requiresLayout() {
return false;
}
}
Now when I'm deploying the WAR to JBoss AS 7.1, it fails, and I get the error:
java.lang.VerifyError: class com.foobar.logging.LogManager$Proxy$_$$_Weld$Proxy$ overrides final method getName.()Ljava/lang/String;
How can I use CDI to inject my EntityManager inside an AppenderSkeleton? Has anyone accomplished JPA persistance in an AppenderSkeleton using CDI?
I also tried not using CDI, but since every other object in my app uses it (JAX-RS classes), it collapses.
EJBs are proxies. AppenderSkeleton has a getName method that is final. I think for your use case, you need to implement Appender directly. This will avoid the bean method getName
However, I have to question the idea of trying to make an appendar an EJB. How are you instantiating it?

Inject HttpServletRequest in CDI SessionScoped bean

I've got a session scoped CDI bean, and I need to somehow access the HttpServletRequest object in this bean's #PostConstruct method. Is it possible? I've tried to Inject such an object, but it results in:
WELD-001408 Unsatisfied dependencies for type [HttpServletRequest] with qualifiers [#Default] at injection point [[field] #Inject ...]
As I understood while googling, the Seam framework has such a functionality, but I have a standard Java EE application on a GlassFish server.
Is it even possible to somehow pass the request to a CDI bean's #PostConstruct method?
As per your comment, you want access to the user principal. You can just inject it like this: #Inject Principal principal; or #Resource Principal principal;, see Java EE 6 Tutorial.
Update
I'll answer your direct question. In Java EE 7 (CDI 1.1) injection of HttpServletRequest is supported out of the box. In Java EE 6 (CDI 1.0) however, this is not supported out of the box. To get it working, include the class below into your web-app:
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {
private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<>();
#Override
public void requestInitialized(ServletRequestEvent sre) {
SERVLET_REQUESTS.set(sre.getServletRequest());
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
SERVLET_REQUESTS.remove();
}
#Produces
private ServletRequest obtain() {
return SERVLET_REQUESTS.get();
}
}
Note: Tested only on GlassFish 3.1.2.2
When using the code from rdcrng be aware of the following:
* The producer-method obtain is dependent-scoped, thus is only called once for application scoped beans (and will resolve to problems for every other request except the first)
* You can solve this with #RequestScoped
* When RequestScoped annotated, you will only get a proxy, and thus you cannot cas it to HttpServletRequest. So you maybe want a producer for HttpServletRequest.
Also note: As per CDI specification link passage 3.6, java ee beans are NOT consideres managed beans. Thus you will end up with two instances of CDIServletRequestProducingListener - one managed by the Java EE container, one managed by the CDI-container. It only works because SERVLET_REQUESTS is static.
Following the modified code for your convenience.
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpServletRequest;
#WebListener
public class CDIServletRequestProducingListener implements ServletRequestListener {
private static ThreadLocal<ServletRequest> SERVLET_REQUESTS = new ThreadLocal<ServletRequest>();
#Override
public void requestInitialized(ServletRequestEvent sre) {
SERVLET_REQUESTS.set(sre.getServletRequest());
}
#Override
public void requestDestroyed(ServletRequestEvent sre) {
SERVLET_REQUESTS.remove();
}
#RequestScoped
#Produces
private HttpServletRequest obtainHttp() {
ServletRequest servletRequest = SERVLET_REQUESTS.get();
if (servletRequest instanceof HttpServletRequest) {
return (HttpServletRequest) servletRequest;
} else {
throw new RuntimeException("There is no HttpServletRequest avaible for injection");
}
}
}

Can't get #Singleton to do anything

Running on JBoss AS7, I have this:
import javax.inject.Singleton;
#Singleton
public class Connections {
private final List<AtmosphereResource> connections = new ArrayList<AtmosphereResource>();
public void add(AtmosphereResource event) {
connections.add(event);
}
}
and this:
import javax.inject.Inject;
public class PubSubAtmosphereHandler extends AbstractReflectorAtmosphereHandler {
#Inject
private Connections connections;
#Override
public void onRequest(AtmosphereResource event) throws IOException {
[...]
connections.add(event); // <---
}
NPE on the designate line. After reading countless pages and examples, this is one of the ways that is repeated dozens of times, yet it doesn't work. I have the empty beans.xml, placed in my WEB-INF. What am I missing here ?
After some research, it turns out that Atmosphere provides (currently broken) hooks for this kind of functionality. That means it IS possible to simply use your normal annotations and have it work with Atmosphere, despite the 'foreign' instantiation.
If you know where your code will be deployed, you can simply overwrite the default noop InjectorProvider class from Atmosphere by having a class with the same name in the same package and having it provide the proper Injector.
I am adding code for JBoss AS7 at the end of this answer, as well as links to code that is supposed to work on Google Guice and Spring, which I have not tested myself.
If you need your code to work on multiple platforms, you will probably need to figure out how to detect what you are running on and then return the appropriate Injector. Since I'm not very familiar with Guice and Spring, I'll leave that exercise to the reader.
Dirty 'first draft' code for JBoss AS7 (remember that this has to go into the declared package to overwrite the default noop provider):
package org.atmosphere.di;
import java.util.NoSuchElementException;
import java.util.ServiceLoader;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.InjectionTarget;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class InjectorProvider {
private InjectorProvider() {}
public static Injector getInjector() {
return LazyProvider.INJECTOR;
}
private static final class LazyProvider {
private static final Injector INJECTOR;
static {
Injector injector = new Injector() {
#Override public void inject(final Object o) {
try {
final BeanManager bm = (BeanManager) new InitialContext().lookup("java:comp/BeanManager");
final CreationalContext cc = bm.createCreationalContext(null);
final InjectionTarget it = bm.createInjectionTarget(bm.createAnnotatedType(o.getClass()));
it.inject(o, cc);
cc.release();
} catch (final NamingException e) {
e.printStackTrace();
}
}
};
try {
injector = ServiceLoader.load(Injector.class).iterator().next();
} catch (final NoSuchElementException e) {}
INJECTOR = injector;
}
}
}
Please note that the wrapping code is taken from the Atmosphere code base, and is a very bad way to do Singletons in Java. You probably don't want to use this 'as is' in production.
Guice injector, untested: https://github.com/Atmosphere/atmosphere/blob/atmosphere-1.0.x/extras/guice/src/main/java/org/atmosphere/guice/GuiceInjector.java
Spring injector, untested: https://github.com/Atmosphere/atmosphere/blob/atmosphere-1.0.x/extras/spring/src/main/java/org/atmosphere/spring/SpringInjector.java
What others are trying to say is that the lifecycle of the PubSubAtmosphereHandler must be controlled by the container (aka JBoss).
In other words the container is responsible for creating and initialising instances of PubSubAtmosphereHandler.
If you or your framework creates this object then the injections will not take place.
It might be possible to get BeanManager using jndi. Then you can get the bean from there.
BeanManager bm = initialContext.lookup("java:comp/BeanManager");
Bean<Connections> bean = (Bean<Connections>) bm.getBeans(Connections.class).iterator().next();
CreationalContext<Connections> ctx = bm.createCreationalContext(bean);
Connections connections = (Connections) bm.getReference(bean, Connections.class, ctx);
connections.add(event);

#Cacheable breaks DependencyInjection

I stumbled upon a case where the AOP proxy created by using #Cacheable breaks the dependency injection in Spring 3.1.1. Here is my scenario:
I have an interface and a class implementing this interface using #Cacheable at the implemented method.
Example interface:
public interface ImgService {
public byte[] getImage(String name);
}
Example implementation:
public class ImgServiceImpl implements ImgService {
#Cacheable(cacheName = "someCache")
public byte[] getImage(String name){//TODO};
protected String someOtherMethod(){//};
}
I also have to JUnit test classes - one which injects the interface and one the implementation:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" })
public class ImgServiceTest {
#Inject
private ImgService;
}
and
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" })
public class ImgServiceImplTest {
#Inject
private ImgServiceImpl;
}
Dependency injection for the interface works fine. However, when I get to injecting the implementation in the second test class I get an "Injection of autowired dependencies failed". I was able to debug it and it appears that ClassUtils.isAssignableValue() wrongly compares the desired type to the proxy class. It is called by DefaultListableBeanFactory. What is even stranger is that if I remove the #Cacheable annotation from the implemented method and add it to some other protected/private method, dependency injection works fine again. Is this a bug and what would be the correct approach to handle this situation?
It's not a bug, it's an expected side-effect of using JDK dynamic proxies for AOP implementation.
Since all calls to the cacheable method of ImgServiceImpl should go through the dynamic proxy of type ImgService, there is no way to inject this dependency into a field of type ImgServiceImpl.
When you move #Cacheable to private or protected method, injection works because #Cacheable doesn't take effect in this case - only public methods can be adviced using proxy-based AOP.
So, you should either declare fields to be injected as ImgService, or configure Spring to use target class-based proxies instead using proxy-target-class = "true".
Yet another option is to configure Spring to use AspectJ-based AOP implementation (requires compile-time or load-time weaving).
It's applicable to all AOP-based features provided by Spring (transactions, security, async execution, cache, custom aspects, etc).
See also:
7.6 Proxying mechanisms
OK, so here is the solution I came up finally. I implemented a simple method that attempts to extract the target object from the proxy based on its implementation of the org.springframework.aop.framework.Advised class:
#SuppressWarnings({"unchecked"})
public static <T> T getTargetObject(Object proxy, Class<T> targetClass) {
if (AopUtils.isJdkDynamicProxy(proxy)) {
try {
return (T) ((Advised)proxy).getTargetSource().getTarget();
} catch (Exception e) {
return null;
}
} else {
return (T) proxy;
}
}
My implementation test class now looks like this:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:META-INF/spring.xml" })
public class ImgServiceImplTest {
#Inject
private ImgService imgService;
private ImgServiceImpl imgServiceImpl;
#PostConstruct
public void setUp() {
imgServiceImpl = getTargetObject(imgService, ImgServiceImpl.class);
}
}

Categories