简体   繁体   中英

How to Disable Dependency Injection in Jersey 2?

I'm new to creating REST web services with Jersey 2. I was able to get a few simple cases going now I'm moving on to "real" work.

I create my own instances of ResourceConfig and populate the ResourceConfig instances with instances of the REST controller returned by Guice:

<!-- language: lang-java -->
final ResourceConfig rc = new ResourceConfig();

//register an *instance* of a REST controller
rc.register(injector.getInstance(MyRestController.class));

Note that since these REST controller instances were provided by Guice, the instances are populated with all necessary dependencies that are marked with the @Inject annotation.

However, when I run the above code to bootstrap Jersey, I see an error like the following:

org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at SystemInjecteeImpl(....

Apparently what is happening is that Jersey is also trying to resolve the @Inject dependencies on the REST controller instance, because it sees the same @Inject annotations that Guice does.

I don't want Jersey to do any dependency injection. I think there are bridges from Jersey to Guice, but based on program requirements that I can't show here, I need to create the REST controller instances myself and ask the Guice Injector for them.

My question: How can I disable the dependency injection in Jersey?

I'm currently using the javax.inject.Inject annotation. Maybe I can use the com.google.inject.Inject annotation instead, thinking that Jersey won't be looking for these annotations. But still, I would rather just turn off dependency injection in Jersey. How can I do that?

Thank you!!

First, your solution:

public class GuiceJerseyManualBridge extends io.dropwizard.Application<Configuration> {

    @Override
    public void run(Configuration configuration, Environment environment) throws Exception {
        JerseyEnvironment jersey = environment.jersey();

        // create the Guice env and its dependencies
        Injector i = Guice.createInjector(new AbstractModule() {
            @Override
            protected void configure() {
                Map<String, String> props = new HashMap<>();
                props.put("testme", "Hello World Guice Inject Test");
                Names.bindProperties(binder(), props);
                bind(HelloResource.class).in(Singleton.class);
            }
        });

        // get instance

        HelloResource resourceInstance = i.getInstance(HelloResource.class);
        jersey.register(new AbstractBinder() {

            @Override
            protected void configure() {
                // teach jersey about your guice dependency 
                bind(resourceInstance).to(HelloResource.class);
            }
        });

        jersey.register(HelloResource.class); // register resource - jersey will discover this from the binding
    }

    @Override
    public void initialize(Bootstrap<Configuration> bootstrap) {
        super.initialize(bootstrap);
    }

    public static void main(String[] args) throws Exception {
        new GuiceJerseyManualBridge().run("server", "/home/artur/dev/repo/sandbox/src/main/resources/config/test2.yaml");
    }

    @Path("test")
    @Produces(MediaType.APPLICATION_JSON)
    public static class HelloResource {


        @Inject
        @Named("testme")
        private String testString;

        public HelloResource() {
            System.err.println("I am created now");
        }

        @GET
        @Path("test")
        public String test(String x) {
            return testString;
        }

    }

}

Please disregard my DropWizard setup. It uses Jersey and it uses Guice, so the registering part is the same.

You are facing 2 dilemmas here:

  1. Jersey DI will attempt to inject fields in your object. That is because it doesn't realise there is an object that is already done. It assumes it has to inject the fields.

So, my solution above does the following:

Bind Guice bean to jersey environment. This will enable jersey to find the bean that you created. Since it is bound into the jersey env, it will not attempt to re-init the bean, but rather treat it as a fully valid object. For this to work, you need to register the Resource as a class argument (triggers jersey to search for a registered bean, or create one if needed)

The other solution you could do is to move your Injects to the Constructor (generally good practice to avoid field injection). Because you register an object, it is illegal to call the constructor again. Therefore jersey will not attempt to do any injection (since there is none to do)

Finally, I don't know how your requirements work, but what you want to do is essentially to manually create a Guice-Jersey Bridge. Teaching your beans to jersey in the way you demonstrate is EXACTLY what the Guice-Jersey bridge does, with the exception that it fixes all those little edge cases (as the one you see now). It is HIGHLY recommended you implement that bridge.

What that bridge does is really to simply delegate creation of beans to guice. That means that it will (1) ask guice for an instance and then create one itself (if Guice returns no instance).

Hiope that helps,

Cheers! Artur

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM