Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey Hk2 injecting @Service annotated classes

For the life of me I cannot get Jersey with hk2 to automatically discover @Service annotated classes and inject them. I have tried to follow every advice on stack overflow, jersey and hk2 documentation and still no luck. I am trying to inject a simple echo service into a Jersey resource. The skeleton is generated from the simple webapp maven archetype for Jersey, which I tried to extend. This is what I have so far:

pom.xml

<build>
  <finalName>sandbox</finalName>
  <plugins>
    <plugin>
      <groupId>org.glassfish.hk2</groupId>
      <artifactId>hk2-inhabitant-generator</artifactId>
      <version>2.3.0</version>
      <executions>
        <execution>
          <configuration>
            <verbose>true</verbose>
          </configuration>
          <goals>
            <goal>generate-inhabitants</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
...
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.glassfish.jersey</groupId>
      <artifactId>jersey-bom</artifactId>
      <version>${jersey.version}</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

<dependencies>
  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
  </dependency>
  <dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2</artifactId>
    <version>2.3.0</version>
  </dependency>
</dependencies>

web.xml

<servlet>
    <servlet-name>Jersey Web Application</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>jersey.config.server.provider.packages</param-name>
        <param-value>my.package.jerseytest</param-value>
    </init-param>
    <init-param>
        <param-name>javax.ws.rs.Application</param-name>
        <param-value>my.package.jerseytest.application.Application</param-value>
    </init-param>    

    <load-on-startup>1</load-on-startup>
</servlet>

my.package.jerseytest.application.Application

public class Application extends ResourceConfig {
    public Application() {
        ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();
    }
}

my.package.jerseytest.service.EchoService

@Service
public class EchoService {
    public String generateResponse(String echo) {
        return echo;
    }
}

my.package.jerseytest.resource.MyResource

@Path("myresource")
public class MyResource {

    @Inject
    EchoService echoService;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String getIt() {
        return echoService.generateResponse("Got it!");
    }
}

I have checked that the inhibitant-generator does in fact run and produce its output, yet when running the Tomcat server GETting http://localhost:8080/sandbox/webapi/myresource I get

SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/sandbox] threw exception [A MultiException has 3 exceptions.  They are:
1. org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)
2. java.lang.IllegalArgumentException: While attempting to resolve the dependencies of my.package.jerseytest.resource.MyResource errors were found
3. java.lang.IllegalStateException: Unable to perform operation: resolve on my.package.jerseytest.resource.MyResource
] with root cause
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(requiredType=EchoService,parent=MyResource,qualifiers={},position=-1,optional=false,self=false,unqualified=null,932014249)

Any ideas what I am missing? I would appreciate any help :(

NB! I know about

  • How does ServiceLocator find @Service and @Contact automatically in HK2?
  • HK2 annotations not being handled
  • https://hk2.java.net/inhabitant-generator.html
  • https://hk2.java.net/2.2.0-b25/getting-started.html
  • https://java.net/jira/browse/HK2-165

but they did not help me...

like image 871
Daniel David Kovacs Avatar asked Oct 07 '14 07:10

Daniel David Kovacs


People also ask

What are the injection annotations?

Annotation Type Inject. Identifies injectable constructors, methods, and fields. May apply to static as well as instance members. An injectable member may have any access modifier (private, package-private, protected, public).

What is HK2 dependency injection?

HK2 (Hundred-Kilobyte Kernel) is a light-weight and dynamic dependency injection framework and is a part of the GlassFish Application Server. HK2. Developer(s) Oracle Corporation. Stable release.


1 Answers

I'm combining the insight I gained from these two questions:

  • How does ServiceLocator find @Service and @Contact automatically in HK2?
  • jersey + grizzly + hk2: Dependency injection, but not into resource

Firstly, use the HK2 Metadata Generator (or the Inhabitant Generator) in your build chain (as you do already). This will scan your source and create META-INF/hk2-locator/default.

Secondly, create a new ServiceLocator, populated with the services from the metadata:

ServiceLocator locator = ServiceLocatorUtilities.createAndPopulateServiceLocator();

Now pass it to Grizzly. Quoting @peeskillet:

Jersey has it's own ServiceLocator, and it's not easy to try a obtain a reference to it. We could give Jersey our ServiceLocator, but Jersey ultimately still creates it's own locator and will populate it with our locator.

ResourceConfig config = new MyApplicationConfig();
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(
    URI.create(BASE_URI),
    config, 
    serviceLocator
);
like image 170
Hank Avatar answered Sep 27 '22 22:09

Hank