Jersey2, Hk2 dependency injection (automatically)

2019-06-09 00:24发布

问题:

Stuck on this problem for a while. I'm trying to integrate Tomcat 9, JDK 10, Jersey 2.23, HK2 (for DI) along with Automatic dependency injection. I've followed this tutorial, but getting below error, I've searched a lot but couldn't find anything on that.

I've used dependency to generate "META-INF/hk2-locator/default" which is getting generate properly.

Dependency

<dependency>
    <groupId>org.glassfish.hk2</groupId>
    <artifactId>hk2-metadata-generator</artifactId>
    <version>2.4.0</version>
</dependency>

Error stack

SEVERE: Servlet [MyApplication] in web application [/javaeeLearning] threw load() exception
java.lang.AbstractMethodError: org.jvnet.hk2.internal.DynamicConfigurationImpl.addIdempotentFilter([Lorg/glassfish/hk2/api/Filter;)V
    at org.glassfish.hk2.utilities.ServiceLocatorUtilities.addClasses(ServiceLocatorUtilities.java:451)
    at org.glassfish.hk2.utilities.ServiceLocatorUtilities.enablePerThreadScope(ServiceLocatorUtilities.java:107)
    at org.glassfish.jersey.internal.inject.Injections._createLocator(Injections.java:141)
    at org.glassfish.jersey.internal.inject.Injections.createLocator(Injections.java:123)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:330)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1124)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1079)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:971)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4829)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5143)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1429)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:944)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:839)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1429)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:944)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:261)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:422)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:770)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:682)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:350)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:492)

Code for automatic DI

import java.io.IOException;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;    
import org.glassfish.hk2.api.DynamicConfigurationService;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.Populator;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ClasspathDescriptorFileFinder;
import org.glassfish.hk2.utilities.DuplicatePostProcessor;
import org.glassfish.jersey.ServiceLocatorProvider;

//This class will cause the HK2 framework to scan your classpath for inhabitants files that are created using the hk2-inhabitant-generator.
public class MyDiscoverableFeature implements Feature {
    @Override
    public boolean configure(FeatureContext context) {
        ServiceLocator locator = ServiceLocatorProvider.getServiceLocator(context);
        DynamicConfigurationService dcs = locator.getService(DynamicConfigurationService.class);
        Populator populator = dcs.getPopulator();
        try {
            populator.populate(new ClasspathDescriptorFileFinder(this.getClass().getClassLoader()),
                    new DuplicatePostProcessor());
        } catch (IOException | MultiException ex) {
            System.out.println("exception occurred " + ex);
        }
        return true;
    }

}    

public class ResourceConfiguration extends ResourceConfig {
    public ResourceConfiguration() {    
//      register(ControllerTest.class);

//      register(new MyBinder());
        this.packages(true, "com.walmart.services.*");

        // for auto scan
        register(MyDiscoverableFeature.class);
    }

}

I've one interface "IUserService" annotated with org.jvnet.hk2.annotations.Contract (@Contract) with implmentation "UserServiceImpl" annotated with org.jvnet.hk2.annotations.Service (@Service)

And i've one controller class:

@Path("/sayHello")
public class ControllerTest {

    @Inject
    private IUserService service;

    @Inject
    private ServicesTest service2;

    @GET
    @Path("/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public String method(@PathParam("name") String msg) {
        return service.method() + msg;
    }

    @GET
    @Path("/v2/{name}")
    @Produces(MediaType.TEXT_PLAIN)
    public String method2(@PathParam("name") String msg) {
        return service.method() + msg;
    }
}

Along with below dependencies

<dependencies>
    <!-- https://mvnrepository.com/artifact/javax/javaee-api -->
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>8.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/javax.ws.rs/javax.ws.rs-api -->     

    <!-- Jersey2.x Dependencies -->

    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-server -->
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>${jersey2.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.glassfish.hk2</groupId>
                <artifactId>hk2-utils</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.glassfish.hk2</groupId>
                <artifactId>hk2-api</artifactId>
            </exclusion>    
            <exclusion>
                <groupId>org.glassfish.hk2.external</groupId>
                <artifactId>javax.inject</artifactId>
            </exclusion>
        </exclusions>
    </dependency>   

    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-common -->
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-common</artifactId>
        <version>${jersey2.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.glassfish.hk2</groupId>
                <artifactId>hk2-utils</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.glassfish.hk2</groupId>
                <artifactId>hk2-api</artifactId>
            </exclusion>
            <exclusion>
                <groupId>org.glassfish.hk2.external</groupId>
                <artifactId>javax.inject</artifactId>
            </exclusion>
        </exclusions>
    </dependency>       
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>${jersey2.version}</version>
        <exclusions>
            <exclusion>
                <groupId>org.glassfish.hk2.external</groupId>
                <artifactId>javax.inject</artifactId>
            </exclusion>
        </exclusions>
    </dependency>     

    <!-- Jersey2.x Dependency injection -->

    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.inject/jersey-hk2 -->
    <dependency>
        <groupId>org.glassfish.jersey.inject</groupId>
        <artifactId>jersey-hk2</artifactId>
        <version>2.27</version>
    </dependency>           

    <!-- https://mvnrepository.com/artifact/org.glassfish.jersey.media/jersey-media-json-jackson -->
    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>${jersey2.version}</version>
    </dependency>

    <!-- generate hk2 metadata (called inhabitant files) t -->
    <!-- https://mvnrepository.com/artifact/org.glassfish.hk2/hk2-metadata-generator -->
    <dependency>
        <groupId>org.glassfish.hk2</groupId>
        <artifactId>hk2-metadata-generator</artifactId>
        <version>2.4.0</version>
    </dependency>
</dependencies>

Update

The above issue is got fixed as soon i remove dependency conflict.

But now, my rest resources are not getting detect at all so i'm getting 404 error on my rest resource.

Though, if i uncomment this line in "ResourceConfiguration" // register(ControllerTest.class); Then it start showing up.

But i don't want to do this for every singel rest resource (not practical ) Please help to solve this problem

@PaulSamsotha; As mention by you to change from ;

this.packages(true, "com.walmart.services.*");

to

this.packages(true, "com.walmart.services");

Gives me below error on server start;

here is the full error;

Don't know the cause of it but as soon as i remove ".*", on server start i get below error.

Sep 27, 2018 2:42:49 PM org.apache.catalina.core.StandardContext loadOnStartup
SEVERE: Servlet [MyApplication] in web application [/javaeeLearning] threw load() exception
java.lang.IllegalArgumentException
    at jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:170)
    at jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:153)
    at jersey.repackaged.org.objectweb.asm.ClassReader.<init>(ClassReader.java:424)
    at org.glassfish.jersey.server.internal.scanning.AnnotationAcceptingListener.process(AnnotationAcceptingListener.java:170)
    at org.glassfish.jersey.server.ResourceConfig.scanClasses(ResourceConfig.java:915)
    at org.glassfish.jersey.server.ResourceConfig._getClasses(ResourceConfig.java:869)
    at org.glassfish.jersey.server.ResourceConfig.getClasses(ResourceConfig.java:775)
    at org.glassfish.jersey.server.ResourceConfig$WrappingResourceConfig._getClasses(ResourceConfig.java:1147)
    at org.glassfish.jersey.server.ResourceConfig.getClasses(ResourceConfig.java:775)
    at org.glassfish.jersey.server.ResourceConfig$RuntimeConfig.<init>(ResourceConfig.java:1206)
    at org.glassfish.jersey.server.ResourceConfig$RuntimeConfig.<init>(ResourceConfig.java:1178)
    at org.glassfish.jersey.server.ResourceConfig.createRuntimeConfig(ResourceConfig.java:1174)
    at org.glassfish.jersey.server.ApplicationHandler.<init>(ApplicationHandler.java:345)
    at org.glassfish.jersey.servlet.WebComponent.<init>(WebComponent.java:392)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:177)
    at org.glassfish.jersey.servlet.ServletContainer.init(ServletContainer.java:369)
    at javax.servlet.GenericServlet.init(GenericServlet.java:158)
    at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1124)
    at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1079)
    at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:971)
    at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4829)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5143)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1429)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:944)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:839)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1429)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1419)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:944)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:261)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:422)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:770)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:682)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:564)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:350)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:492)

Moreover i found the above line does not makking any sense, even i remove it completly with register of controller everything works fine.