jersey-2.0spring-jersey

Using JSR-330 annotations with Jersey 2 + Spring


I have been trying to use Spring 4 with Jersey 2 and notice that using the jersey-spring3 extension there is no way to make @Named annotated resources managed by Spring. They must be annotated with @Component to be managed by Spring.

If a resource is annotated with @Named HK2 seems to "take over" managing that resource.

Resource

import com.example.jersey.spring.Greeting;
import java.util.logging.Logger;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Named
@Singleton
@Path("resource")
public class Resource {

    private static final Logger logger = Logger.getLogger("Resource");

    public void init() {
        logger.info("Creating -> " + this + " injected with -> " + greeting);
    }

    @Inject
    private Greeting greeting;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        logger.info("Working on " + this + " Greeting " + greeting);
        return "Got it!";
    }
}

With the following Spring applicationContext

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:context="http://www.springframework.org/schema/context"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
      http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" 
   default-init-method="init">

    <context:component-scan base-package="com.example.jersey.webapp"/>
    <bean id="greeting" class="com.example.jersey.spring.Greeting"/>
</beans>

Results in the following log messages being printed on start-up

Oct 18, 2017 3:11:44 PM org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor <init>
INFO: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
Oct 18, 2017 3:11:44 PM com.example.jersey.webapp.Resource init
INFO: Creating -> com.example.jersey.webapp.Resource@6e199bab injected with -> com.example.jersey.spring.Greeting@533b3005
Oct 18, 2017 3:11:45 PM org.springframework.web.context.ContextLoader initWebApplicationContext
INFO: Root WebApplicationContext: initialization completed in 249 ms

And after a couple of GET calls.

Oct 18, 2017 3:11:56 PM com.example.jersey.webapp.Resource getIt
INFO: Working on com.example.jersey.webapp.Resource@40328bbc Greeting com.example.jersey.spring.Greeting@533b3005
Oct 18, 2017 3:12:03 PM com.example.jersey.webapp.Resource getIt
INFO: Working on com.example.jersey.webapp.Resource@40328bbc Greeting com.example.jersey.spring.Greeting@533b3005

So it appears Spring does create the bean but that is not the one thats used to service the requests. However if instead of Named, Component is used the entire lifecycle is managed by Spring.

Is there a way to use the standard @Named annotation and ensure Spring manages the lifecycle of resource completely?


Solution

  • I don't think that there is a way to disable HK2.

    From latest Jersey-2 Userguide:

    the resources must themselves be managed by Spring, by annotating with @Component, @Service, @Controller or @Repository

    Spring recommends the use of the more specific annotations @Service, @Controller and @Repository.

    From the Spring 4.3.12 Documentation §7.10.1:

    @Component and further stereotype annotations

    The @Repository annotation is a marker for any class that fulfills the role or stereotype of a repository (also known as Data Access Object or DAO). Among the uses of this marker is the automatic translation of exceptions as described in Section 20.2.2, “Exception translation”.

    Spring provides further stereotype annotations: @Component, @Service, and @Controller. @Component is a generic stereotype for any Spring-managed component. @Repository, @Service, and @Controller are specializations of @Component for more specific use cases, for example, in the persistence, service, and presentation layers, respectively. Therefore, you can annotate your component classes with @Component, but by annotating them with @Repository, @Service, or @Controller instead, your classes are more properly suited for processing by tools or associating with aspects. For example, these stereotype annotations make ideal targets for pointcuts. It is also possible that @Repository, @Service, and @Controller may carry additional semantics in future releases of the Spring Framework. Thus, if you are choosing between using @Component or @Service for your service layer, @Service is clearly the better choice. Similarly, as stated above, @Repository is already supported as a marker for automatic exception translation in your persistence layer.