Correct way to integrate JAX-RS with CDI?

I used to integrate services and DAO beans in Jersey REST resources, annotating them with @Path

following Java EE tutorial

In general, for JAX-RS to work with beans corporation, you need to annotate the bean class with @Path to convert it to the root resource class. You can use @Path annotation with stateless session beans and singleton POJO beans.

So my code was something like this:

@Path("/")
public class ServiceResource {
   @Inject
   private AccountService accountService;

   @GET
   @Path("/account/get")
   public Account getAccount(@QueryParam("id") String id) {
     return accountService.get(id);
   }
}

@javax.inject.Singleton
@Path("")
public class AccountService {
   public Account get(String id){...}
}

      

Now I started integrating Quartz Job into my application and I wanted to find a way to insert mine AccountService

inside jobs like this

public class AccountJob implements Job {
  @Inject
  private AccountService accountService;

  @Override
  public void execute(JobExecutionContext jec) throws JobExecutionException {
    accountService.updateAllAccounts();
  }
}

      

I found this answer that says to use DeltaSpike

to get the job done, so I added the following dependencies to mine pom.xml

and don't add more line of code for any class, i.e. invalidation AccountService

for mine Job

works fine

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-scheduler-module-api</artifactId>
    <version>1.7.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-scheduler-module-impl</artifactId>
    <version>1.7.2</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-api</artifactId>
    <version>1.7.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.cdictrl</groupId>
    <artifactId>deltaspike-cdictrl-weld</artifactId>
    <version>1.7.2</version>
    <scope>runtime</scope>
</dependency>

      

However , I realized that when I remove @Path("")

from AccountService

, its instance is still injected within within ServiceResource

, so I ask the following questions:

  • Why did adding dependencies DeltaSpike

    allow injecting my beans without being used @Path

    on them?
  • Looking for more, I figured out what is DeltaSpike

    using Weld

    for internal injection, and since I already use GlassFish 4.0

    , I know that it Weld

    already exists, so why doesn't injection work by default in the class Job

    and in the class ServiceResource

    without adding @Path

    to my beans? In fact, why is the addition @Path

    even suggested in the Java tutorial?
  • Are there any bad side effects that I don't see in my code because I think I am mixing several DI methods here without understanding how they work?

Update: . After more searching, I realize that it Jersey

does not use Weld

for dependency injection, instead it uses HK2

, another structure which also turns out to be part of GlassFish

, when I try to inject AccountService

without using @Path

it shows the following exception

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object to inject in SystemInjecteeImpl (requiredType = AccountService , parent = ServiceResource , qualifiers = {} ...

So this updates the questions to the following:

  • How to do injections HK2

    ? // Without using @Path

    as pointed out in the Java EE tutorial
  • If I was able to do DI

    with using HK2

    , can I use Quartz DeltaSpike

    to execute DI

    for the job? Can I mix two CDI fluids together to scan classes and inject?

I have put my source code on pastebin; pom.xml

here and Java

here

+3


source to share


3 answers


You don't need to provide an annotation Path

on the AccountService

CDI bean. If CDI is enabled in your application (either with empty beans.xml in CDI 1.0 or in discovery mode = everything in CDI> 1.0), you can have @Inject

any CDI bean in your JAX-RS resource. Therefore, you just need to write the following class:

@Path("/")
public class ServiceResource {
   @Inject
   private AccountService accountService;

   @GET
   @Path("/account/get")
   public Account getAccount(@QueryParam("id") String id) {
     return accountService.get(id);
   }
}

@javax.inject.Singleton
public class AccountService {
   public void Account get(String id){...}
}

      

The article you linked in your post is about mixing EJB and CDI annotations. For example, you can combine annotations @Stateless

and @Path

. This is interesting, for example, because you can:

  • Benefits of EJB transaction on Rest resource (even though you can use hook bindings @Transactional

    )
  • Install resource pool
  • and etc.

Note that this all works without the help of the deltaspike dependency.



For your second question, since Quartz manages its threads, the classes are not handled by CDI, so you cannot inject beans into the quartz classes. The purpose of the deltaspike module is to allow CDI beans to be injected into Quartz Jobs. Internally, deltaspike manages CDI contexts.

EDIT

For your latest questions:

  • The problem with HK2 comes from missing dependencies (in the app or server). As mentioned in a previous comment, I was able to deploy your application on Glassfish 4 (build 89) with the source files you provided.

  • As far as CDI integration with quartz goes, I think it's best to implement your own JobFactory

    and speed things up with BeanManager

    . Take a look at this link: https://devsoap.com/injecting-cdi-managed-beans-into-quarz-jobs/

+4


source


First of all, the nested resources (beans) and Jersey endpoint class (injection point) must be CDI-Aware. It must be recognized by CDI. We can use bean -discovery-mode = "all" - then CDI scan ALL classes or bean -discovery-mode = "annotated" and MARK our class with PROPER annotation: hence: Bean definition of annotations . I prefer @Dependent or @RequestScoped

Then we have to use Jersey Extension

<dependency>
  <groupId>org.glassfish.jersey.ext.cdi</groupId>
  <artifactId>jersey-cdi1x-servlet</artifactId>
  <version>{version}</version>
  <scope>runtime</scope>
</dependency>

      



`

for CDI connection with HK2 detection engine. Here is the Official Oracle Guide

0


source


The default bean.xml lookup mode (in Java EE 7) is "annotated". This means that only beans that have CDI annotations are recognized and managed by CDI.

Your AccountJob class is not annotated. If you want CDI to be able to inject a service into it, you need to annotate it with a scope annotation, for example. @ApplicationScoped.

Another option is to create a CDI producer to create AccountJob beans. See: http://docs.jboss.org/weld/reference/latest/en-US/html_single/#_producer_methods

-2


source







All Articles