简体   繁体   中英

Getting hk2 and Jersey to inject classes

How can I get Jersey to inject classes without creating and registering factories on a one-for-one basis?

I have the following config:

public class MyConfig extends ResourceConfig {
    public MyConfig() {
        register(new AbstractBinder() {
            @Override
            protected void configure() {
                bindFactory(FooFactory.class).to(Foo.class);
                bindFactory(BazFactory.class).to(Baz.class);
            }
        });
    }
}

hk2 will now successfully inject Foo and Baz:

// this works; Foo is created by the registered FooFactory and injected
@GET
@Path("test")
@Produces("application/json")
public Response getTest(@Context Foo foo) {
    // code
}

But that's not my goal. My goal is to inject objects that wrap these classes. There are many and they each consume different combinations of Foo and Baz. Some examples:

public class FooExtender implements WrapperInterface {

    public FooExtender(Foo foo) {
        // code
    }
}

public class FooBazExtender implements WrapperInterface {

    public FooBazExtender(Foo foo, Baz baz) {
        // code
    }
}

public class TestExtender implements WrapperInterface {

    public TestExtender(Foo foo) {
        // code
    }
    // code
}

And so on.

The following does not work:

// this does not work
@GET
@Path("test")
@Produces("application/json")
public Response getTest(@Context TestExtender test) {
    // code
}

I could create a factory for each and register it in my application config class, using the bindFactory syntax like I did with Foo and Baz. But that is not a good approach due to the number of objects in question.

I have read much of the hk2 documentation, and tried a variety of approaches. I just don't know enough of how hk2 actually works to come up with the answer, and it seems like a common enough problem that there should be a straightforward solution.

Factories are really only needed for more complex initializations. If you don't need this, all you need to do is bind the service

@Override
protected void configure() {
    // bind service and advertise it as itself in a per lookup scope
    bindAsContract(TestExtender.class);
    // or bind service as a singleton
    bindAsContract(TestExtender.class).in(Singleton.class);
    // or bind the service and advertise as an interface
    bind(TestExtender.class).to(ITestExtender.class);
    // or bind the service and advertise as interface in a scope
    bind(TestExtender.class).to(ITestExtender.class).in(RequestScoped.class);
}

You also need to add @Inject on the constructors so HK2 knows to inject the Foo and Baz

@Inject
public TestExtender(Foo foo, Baz baz) {}

I wound up using FastClasspathScanner to grab classes from the package(s) I was interested in. Then I called the appropriate bind methods ( bindAsContract or bind ) in batches, as mentioned in Paul Samsotha's answer (after also adding the appropriate @Inject annotations).

That seemed to be the most expedient method available to emulate autoscanning and avoid having to manually register each class.

It feels like a hack and I'd be surprised if hk2 doesn't have a better method baked in.

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