Thursday, May 2, 2013

Jersey REST JAX-RS + Glassfish + EJB = Success!

A well known issue with Jersey prevents injecting EJB's into a RESTfull service. Several walkarounds were suggested (http://stackoverflow.com/questions/3027834/inject-a-ejb-into-jax-rs-restfull-service), but most of them are error-prone or just complicated.
If you are using Glassfish, by invoking InjectionManager.injectInstance(yourRestObject) you would inject your EJBs/Resources/@PersistenceContexts into yourRestObject, and solve the issue effortless. One way to accomplish it might be implementing an abstract constructor:

I guess some of you would raise an eyebrow about the sneakyThrow part. SneakyThrow is a nice (and dirty) trick I've learned from Lombok, which allow you to throw checked exceptions without declearing them. This is useful here because otherwise you would have to either: a) wrap your InjectionException with RuntimeException, which is not exactly the same as throwing InjectionException, or b) implement an empty YourRESTService() throws NamingException, InjectionException constructor for each RESTful service, which is ugly. Sneakily throwing the InjectionException (and the NamingException on odd cases) address both issues.

If you're using Maven, you'll need to have the following dependency added to your pom:


There is an important pitfall and limitation here: you cannot put your injector in a @PostConstract method, as the InjectionManager will invoke itself recursively. On the same note, since Jersey invokes @PostConstract methods as well, every method that is annotated with @PostConstract will be invoked twice upon construction (instead of once). In both invocations your injections will be in place (i.e not null), but you should still consider this fact into your design, especially if the @PostConstract's are expensive or have side effects.

P.S.
When thinking about it, if you really insist you can removing the container-common dependency from the compiler classpath, and invoke injectInstance() using reflection. But I can't find any good reason to do that.