Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey custom Context injection

I tried implementing custom context injection just like in this answer:

@Provider
public class DaoContextProvider extends SingletonTypeInjectableProvider<Context,Bar> {

    public DaoContextProvider() {
        super(Bar.class, new Bar("haha"));
    }

}

And here's my controller class, to witch I want to inject my context:

@Path("foo")
public class Foo {

    @Context
    private Bar message;

    @GET
    public String index() {
        return String.format("%s", message );
    }

}

But in response message is null.

I tried adding my context provider to singletons, as recomended:

@javax.ws.rs.ApplicationPath("webresources")
public class ApplicationConfig extends Application {

    public ApplicationConfig() {
        getSingletons().add(new DaoContextProvider());
    }
//...

But then my artifact does not even deploy, and provides me with this error:

Artifact server:war exploded: java.io.IOException: com.sun.enterprise.admin.remote.RemoteFailureException: Error occurred during deployment: Exception while loading the app : java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: org.apache.catalina.LifecycleException: java.lang.UnsupportedOperationException. Please see server.log for more details.

I would provide server.log, as described in exception, but I dont know where to find this log.

like image 522
Ben Avatar asked Oct 20 '22 04:10

Ben


1 Answers

The set returned from getSingletons() is unmodifiable. Instead we need to override the method

@Override
public Set<Object> getSingletons() {
    Set<Object> singletons = new HashSet<>();
    singletons.add(new new DaoContextProvider());
    return singletons;
}

Note though that a direct Application subclass is limited in functionality compared to the Jersey specific way. In Jersey, the preferred approach is to use a ResourceConfig subclass (which is actually a subclass of Application). For example (you can use PackagesResourceConfig to scan packages).

@ApplicationPath("/webresources")
public class AppConfig extends PackagesResourceConfig {
    
    public AppConfig() {
        // scans the package and sub-packages.
        super("package.where.all.your.resource.and.providers.are");
        getProperties().put("some properites", "to set");
        getContainerRequestFilters().add(new SomeFiltersToRegister());
        getProviderSingletons().add(new SomeProvidersToAdd());
        // see the ResourceConfig API for more methods.
    }
}

This will scan for @Path and @Provider annotated classes, so we don't need to explicitly register everything. Though some providers will need to be explicitly registered. Your particular provider doesn't need to be registered though. It i picked up in the package scan.


UPDATE

Ok since you say you are using Glassfish 4.1, the first thing you should understand is that Glassfish 4 uses Jersey 2.x. So any Jersey 1.x dependencies/jars you have, you should get rid of them. Use only Jersey 2.x dependencies, and make sure that they are only compile-time dependencies, as you do not want conflicting versions making it's way to Glassfish, that already has a version of them.

What this means is that your current implementation of the DaoContextProvider will not work. The SingletonTypeInjectableProvider is Jersey 1.x class, and the Jersey 2.x runtime will just ignore it.

In Jersey 2.x there are a few ways to configure injectable objects. One way is to create a Factory for the object. For example.

public class DaoContextProvider implements Factory<Bar> {

    @Override
    public Bar provide() {
        return new Bar("boo hoo!");
    }

    @Override
    public void dispose(Bar bar) {}
}

In Jersey 2.x, the API for ResourceConfig has change, and we can extend it directly. For example

@ApplicationPath("/webresources")
public class AppConfig extends ResourceConfig {

    public AppConfig() {
        
        packages("com.stackoverflow.jersey");
        
        register(new AbstractBinder(){
            @Override
            protected void configure() {
                bindFactory(DaoContextProvider.class)
                        .to(Bar.class)
                        .in(RequestScoped.class);
            }
        });
    }
}

You can see the AbstractBinder. That is how we register the DaoContextProvider with the Bar class. So now Bar can be injected to your resource classes.

The only Maven dependency you need to pull everything else in, is

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.19</version>
    <scope>provided</scope>
</dependency> 

Notice the provided scope, so that it does not get built to the war. If you are not using Maven, then grab all the jars in the Jersey JAX-RS 2.0 RI bundle. Remember that you should make them only compile time dependencies. They should no get built into the war.

See Also:

  • Custom Injection and Lifecycle Management
like image 97
Paul Samsotha Avatar answered Nov 02 '22 07:11

Paul Samsotha