How do I allow CDI injection of resources into restful web service resources? I am running on standard java using weld 2 (cdi), jersey (jaxrs), and grizzly (web server). H
After seeing this stackoverflow post, I implemented the following solution. Not sure if it is the best route to take, but it worked.
I created an hk2 Binder and registered the Binder:
public class WebServiceBinder extends AbstractBinder {
@Override
protected void configure() {
BeanManager bm = getBeanManager();
bind(getBean(bm, StudentRepository.class))
.to(StudentRepository.class);
}
private BeanManager getBeanManager() {
// is there a better way to get the bean manager?
return new Weld().getBeanManager();
}
private <T> T getBean(BeanManager bm, Class<T> clazz) {
Bean<T> bean = (Bean<T>) bm.getBeans(clazz).iterator().next();
CreationalContext<T> ctx = bm.createCreationalContext(bean);
return (T) bm.getReference(bean, clazz, ctx);
}
}
Then modified the ResourceConfig instantiation from above to:
final ResourceConfig resourceConfig = new ResourceConfig()
.packages("training.webservice")
.register(new JacksonFeature())
.register(new WebServiceBinder());
The selected answer dates from a while back. It is not practical to declare every binding in a custom HK2 binder. I just had to add one dependency. Even though it was designed for Glassfish it fits perfectly into other containers. I'm using Tomcat / Grizzly.
<dependency>
<groupId>org.glassfish.jersey.containers.glassfish</groupId>
<artifactId>jersey-gf-cdi</artifactId>
<version>2.14</version>
</dependency>
Here is an example with JerseyTest (same principle if you run it from a main method). I just had to declare a dependency on weld-se and declare a Weld container before instantiating my resources - as you also did - and it works out of the box.
public class GrizzlyTest extends JerseyTest {
private Weld weld;
private WeldContainer container;
@Override
protected Application configure() {
weld = new Weld();
container = weld.initialize();
return new ResourceConfig(MyResource.class);
}
@Test
public void test() {
System.out.println(target("myresource").request().get(String.class));
}
@After
public void after() {
weld.shutdown();
}
}
Since at least Weld 2.2.0.Final there is no need to mess up with HK2 Binder.
As official Weld documentation states you just need to register org.jboss.weld.environment.servlet.Listener
. Code snipped from doc:
public class Main {
public static void main(String[] args) throws ServletException, LifecycleException {
Tomcat tomcat = new Tomcat();
Context ctx = tomcat.addContext("/", new File("src/main/resources").getAbsolutePath());
Tomcat.addServlet(ctx, "hello", HelloWorldServlet.class.getName());
ctx.addServletMapping("/*", "hello");
ctx.addApplicationListener(Listener.class.getName());
tomcat.start();
tomcat.getServer().await();
}
public static class HelloWorldServlet extends HttpServlet {
@Inject
private BeanManager manager;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
resp.getWriter().append("Hello from " + manager);
}
}
}
Above servlet listener manages the whole lifecycle of the Weld container. So there is no need to:
Weld weld = new Weld();
WeldContainer container = weld.initialize();
UPDATE As @EdMelo pointed out, Grizzly HTTP server is not a fully compliant Servlet container. I didn't know this, thanks for this hint. So I'm not sure, if my answer still applies here.