This solution works well, and I wanted to share what I found to enable CDI on knitwear resources.
Here is the easiest bean ever:
package fr.test; import javax.annotation.PostConstruct; import javax.enterprise.context.RequestScoped; @RequestScoped public class Test { private int i; @PostConstruct public void create() { i = 6; } public int getI() { return i; } }
In your resource class, we simply introduce this bean, as it would in any normal context:
package fr.test; import javax.inject.Inject; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; @Path("/login") public class LoginApi { @Inject private Test test; @GET @Produces("text/plain") public String getIt() { return "Hi there!" + test; } }
And here is the key. We define a Jersey "InjectionProvider" that will be responsible for permitting beans:
package fr.test; import javax.inject.Inject; import java.lang.reflect.Type; 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; import fr.xxxxxxxxxx.ApplicationBeans; @Provider public class InjectionProvider implements InjectableProvider<Inject, Type> { public ComponentScope getScope() {
InjectableProvider is introduced with the type of annotation we are processing and the type of context (here, the regular java type)
ApplicationBeans is just a simple helper to resolve beans. Here is its content:
package fr.xxxxxxxxxx; import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.Collection; import java.util.Set; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.spi.CreationalContext; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.inject.Inject; import javax.naming.InitialContext; import javax.naming.NamingException; import fr.xxxxxxxxxxxxx.UnexpectedException; @ApplicationScoped public class ApplicationBeans { protected static ApplicationBeans instance; @Inject private BeanManager beanManager; public static ApplicationBeans instance() { if (instance == null) { BeanManager beanManager; InitialContext ctx = null; try { ctx = new InitialContext(); beanManager = (BeanManager)ctx.lookup("java:comp/BeanManager"); }catch(NamingException e) { try { beanManager = (BeanManager)ctx.lookup("java:app/BeanManager"); }catch(NamingException ne) { throw new UnexpectedException("Unable to obtain BeanManager.", ne); } } instance = getBeanFromManager(beanManager, ApplicationBeans.class); } return instance; } public static <T> T get(final Class<T> beanType, Annotation... annotations) { return instance().getBean(beanType, annotations); } public <T> T getBean(final Class<T> beanType, Annotation... annotations) { return getBeanFromManager(beanManager, beanType, annotations); } @SuppressWarnings("unchecked") private static <T> T getBeanFromManager(BeanManager beanManager, final Class<T> beanType, Annotation... annotations) { Set<Bean<?>> beans = beanManager.getBeans(beanType, annotations); if (beans.size() > 1) { throw new UnexpectedException("Many bean declarations found for type %s (%s)", beanType.getSimpleName(), beansToString(beans)); } if (beans.isEmpty()) { throw new UnexpectedException("No bean declaration found for type %s", beanType.getSimpleName()); } final Bean<T> bean = (Bean<T>)beans.iterator().next(); final CreationalContext<T> context = beanManager.createCreationalContext(bean); return (T)beanManager.getReference(bean, beanType, context); } private static String beansToString(Collection<Bean<?>> beans) { String[] beansLabels = new String[beans.size()]; int i = 0; for (final Bean<?> bean : beans) { beansLabels[i++] = bean.getName(); } return Arrays.toString(beansLabels); } }
Hope this helps those who want to incorporate CDI injection into their resources in Jersey.
Until!