tombo_189
tombo_189

Reputation: 384

Difference between ResourceConfig and ServletContextListener for Jersey Rest Service

I want to initialize a Jersey Rest service and introduce a global application-wide variable which should be calculated at application start up-time and should be available in each rest resource and each method (here indicated by the integer globalAppValue=17, but will be a complex object later).

In order to initialize the service and calculate the value once at start up I found two practices: The general ServletContextListener and the Jersey ResourceConfig method. But I have not understood what is the difference between both of them? Both methods fire at start up (both System.out-messages are printed).

Here is the implementation of my ServletContextListener which works fine:

public class LoadConfigurationListener implements ServletContextListener
{
    private int globalAppValue = 17;

    @Override
    public void contextDestroyed (ServletContextEvent event)
    {
    }

    @Override
    public void contextInitialized (ServletContextEvent event)
    {
        System.out.println ("ServletContext init.");

        ServletContext context = event.getServletContext ();
        context.setAttribute ("globalAppValue", globalAppValue);
    }
}

And this is the implementation of the Jersey Rest ResourceConfig-method in which the ServletContext is not available. Neither is this Application-object later availabe by injection with the resource-methods:

@ApplicationPath("Resources")
public class MyApplication extends ResourceConfig
{
    @Context
    ServletContext context;

    private int globalAppValue = 17;

    public MyApplication () throws NamingException
    {
        System.out.println ("Application init.");

        // returns NullPointerException since ServletContext is not injected
        context.setAttribute ("globalAppValue", 17);
    }

    public int getAppValue ()
    {
        return globalAppValue;
    }
}

This is the way I would like to gain access in the resource methods to the global value:

@Path("/")
public class TestResource
{
    @Context
    ServletContext context;
    @Context
    MyApplication application;

    @Path("/test")
    @GET
    public String sayHello () throws SQLException
    {
        String result = "Hello World: ";

        // returns NullPointerException since application is not injected
        result += "globalAppValue=" + application.getAppValue ();

        // works!
        result += "contextValue=" + context.getAttribute ("globalAppValue");

        return result;
    }
}

So while the classic ServletContextListener works fine I got several problems to use the ResourceConfig/Application, but would prefer this way because it seems to integrate more natively into Jersey. So my question is which way would be the best practice to use. Thanks!

Upvotes: 5

Views: 5075

Answers (2)

tombo_189
tombo_189

Reputation: 384

no sory, this produces "value=null" as an output if GET /test/ is called.

package rest;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;

@Path("/test")
public class TestResource
{
    @Context
    Application application;

    @GET
    public String sayHello () 
    {
        String result = "value=" + application.getProperties ().get ("value");

        return result;
    }
}

ApplicationPath set here to "resources" ?

package rest;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.server.ResourceConfig;

@ApplicationPath("resources")
public class MyApplication extends ResourceConfig
{
    public MyApplication ()
    {
        property ("value", 17);
        System.out.println (getProperties ());
    }
}

EDIT: For those who followed our discussion, the solution/problem is as follows. With the servlet deployment part of my web.xml, first I wrote wrongly

<servlet-mapping>
    <servlet-name>Jersey REST Service</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

After having deleted the * and changed the url-pattern to <url-pattern>/</url-pattern> (without *) and respectively changing

@ApplicationPath("/")
public class MyApplication extends ResourceConfig

it finally worked out. So the ApplicationPath must be the same as in the Servlet-Url in the web.xml in order to have the injection in the method class correctly done.

Upvotes: 0

Paul Samsotha
Paul Samsotha

Reputation: 209052

You could just set a property in the ResourceConfig by just calling property( key, value ).

public MyApplication() {
    property("MyProp", "MyValue");
}

In your resource class, your are only allowed to inject the super abstract class javax.ws.rs.core.Application, which ResourceConfig extends from.

Then what you can do is call one of standard the Application API methods to get set properties. That method of course is named getProperties(), which returns a map of properties.

@Path("/")
public class TestResource
{
    @Context
    Application application;

    @GET
    public String get() {
        String value = (String)application.getProperties().get("MyProp");
    }
}

Also by using the property method on the ResourceConfig, that property is put into a global javax.ws.rs.core.Configuration object, which is also injectable. So instead of Application, you could inject Configuration

@Path("/")
public class TestResource
{
    @Context
    Configuration config;

    @GET
    public String get() {
        String value = (String)config.getProperty("MyProp");
    }
}

See Also:

Upvotes: 5

Related Questions