5

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!

tombo_189
  • 384
  • 5
  • 22

2 Answers2

5

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:

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Thanx, that way works! But what method is to be preferred within Jersey Rest webservices? The ServletContextListener or the Application-ResourceConfig-way? – tombo_189 Sep 21 '15 at 10:30
  • I prefer sticking with Jersey. There is no need to involve the servlet container if you don't need to. It like poor man's Dependency Injection. Jersey has all the capability of handling DI. – Paul Samsotha Sep 21 '15 at 10:33
  • I seem to be stuck again: When I use `property ("value", 17);` within the Constructor of `public class Application extends ResourceConfig` I can reread the property immediately there, but not in my Resource-method. There the injection `@Context Application application;` works (application is not null) but application.getProperties () returns null. So are there any special annotaton to be set within the Application class? Could you please extend the Application class in your previous example to a full class with annotations and imports? – tombo_189 Sep 21 '15 at 14:30
  • It's exactly how you have it in your original post. `MyApplication extends ResourceConfig`. No other annotations besides the `@ApplicationPath` – Paul Samsotha Sep 21 '15 at 14:34
  • could you please take a look at the answer (my code) below? – tombo_189 Sep 21 '15 at 15:05
  • @peeskillet would this be a valid argument in favour of ServletContextListener: ResourceConfig is Jersey-specific, and ServletContextListener is not, hence the ServletContextListener-approach allows us to replace the JAX-RS implementation if we later decide that we want to use some other implementation? – Janus Varmarken Aug 11 '16 at 18:53
  • @peeskillet how do we handle contextdestroyed with ResourceConfig subclass.. or would we need servletcontextlistener impl for that – zee Jan 26 '17 at 10:08
  • @zee you can use an [application event listener](https://jersey.java.net/nonav/documentation/latest/monitoring_tracing.html#monitoring) – Paul Samsotha Jan 26 '17 at 10:11
  • @peeskillet i added my MyApplicationEventListener implements ApplicationEventListener class and registered it in my subclass of ResourceConfig as register(com.MyApplicationEventListener.class); but the listener onEvent is not called – zee Jan 26 '17 at 10:28
  • @zee is your ResourceConfig even being used? Why don't you post another question and I'll have a look at it. – Paul Samsotha Jan 26 '17 at 10:29
  • @peeskillet yes it is being used.. as my APIs are called. let me post other question and add a link here.. thx – zee Jan 26 '17 at 10:31
0

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.

tombo_189
  • 384
  • 5
  • 22