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
but they did not help me...
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).
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.
I'm combining the insight I gained from these two questions:
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
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With