1

For simplifying our web services I'd like to introduce a custom MyObj class using the Jersey framework in version 2.34 and want to inject the created instances via the @Context annotation.

I have two questions:

  1. Assuming a web service method @GET test(@Context MyObj obj), how can I control when instances of MyObj are created in respect to the execution of existing servlet request filters?

  2. To create instances of MyObj, I already have a working example based on HK2's Factory's (see below). Since I observed that my factory class gets instantiated twice, and Jersey 2.26+ recomments to use the newer approach based on Supplier's, I tried to convert my example. Unfortunately, configure() won't be called in the provided Binder implements Supplier class, and thus, no objects get created. How can I get this working? (Btw., In both cases, Binder and BinderHK are registered via jersey.config.server.provider.classnames in my web.xml.)

Thank you for any help.

Working HK2 Factory example:

public class MyObjHK {}

import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
public class BinderHK
extends AbstractBinder {
    @Override protected void configure() {
        bindFactory(MyObjFactoryHK.class).to(MyObjHK.class).in(RequestScoped.class);
    }
}

import org.glassfish.hk2.api.Factory;
public class MyObjFactoryHK
implements Factory<MyObjHK> {
    @Override public MyObjHK provide() {return new MyObjHK();} // ok
    @Override public void dispose(MyObjHK instance) {};
}

public class API_HK2 {
    @GET
    public static Response myobjhk(@Context MyObjHK obj) {
        System.out.println("called hk, obj="+obj); // ok
        return Response.ok().build();
    }
}

Not working Supplier example:

public class MyObj {}

import org.glassfish.jersey.internal.inject.AbstractBinder;
import org.glassfish.jersey.process.internal.RequestScoped;
public class Binder
extends AbstractBinder {
    @Override protected void configure() { // not called ???
        bindFactory(MyObjFactory.class).to(MyObj.class).in(RequestScoped.class);
    }
}

import java.util.function.Supplier;
public class MyObjFactory
implements Supplier<MyObj> { 
    @Override public MyObj get() {return new MyObj();}
}

public class API {
    @GET
    public static Response myobj(@Context MyObj obj) {
        System.out.println("called, obj="+obj); // null ???
        return Response.ok().build();
    }
}
user27772
  • 522
  • 1
  • 4
  • 18

1 Answers1

1

The binder isn't something that can be registered with the jersey.config..classnames init-param. You need to either register it with a ResourceConfig or with Feature (and register the Feature with the init-param)

@Provider
public class MyFeature implements Feature {
    @Override
    pubic boolean configure(FeatureContext ctx) {
        ctx.register(new MyBinder());
        return true;
    }
}
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanks, but the MyFeature/Binder approach also does not work for me (I tried registering using init-param jersey.config.server.provider.classnames as well as jersey.config.server.provider.packages along with @Provider). Also, in contrast to your saying, registration of _BinderHK extends AbstractBinder_ (see my working example below) does work even without using a Feature. Any more hints are welcome. – user27772 Apr 26 '21 at 08:20
  • In the example in https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/user-guide.html, chapter 24.1, an implementation of AbstractBinder is directly registered. It matches the explaination: "While the individual injection binding implementations vary and depend on your use case, to enable your custom injection extension in Jersey, you must register your custom HK2 Binder implementation in your application ResourceConfig!". Now, I wonder if web.xml is not enough but I really have to explicitely use a ResourceConfig instance (I didn't test it yet)? – user27772 Apr 26 '21 at 08:57
  • THat documentation has not been updated in years. Especially in regards to HK2. As you can see, it still uses HK2, even though that is no longer the recommended usage. Unless you specifically need HK2 features, all you injection imports should be from `jersey.internal.inject` package. – Paul Samsotha Apr 26 '21 at 15:48
  • Ok, while setting up a complete example I obviously found the problem. I accidentally annotated both the _AbstractBinder_ as well as the _Feature_ class with _@Provider_. After removing the annotation in the _AbstractBinder_ class and keep it only in the _Feature_ class (according to your answer), the problem is gone. Thank you for your support. I have one last question: Is it correct that I still have to keep the _org.glassfish.jersey.inject - jersey-hk2_ dependency (in version 2.34 in pom.xml) to keep things working? – user27772 Apr 28 '21 at 08:12
  • [Yes it's still required](https://stackoverflow.com/a/51217530/2587435). – Paul Samsotha Apr 28 '21 at 08:34