Industrious
Industrious

Reputation: 417

Get ServletContext in Application

Could you possibly explain how I can get the ServletContext instance in my Application's sub-class? Is it possible? I have tried to do it like in the following snippet but it does not seem to work - the ctx is not set:

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

//...

@ApplicationPath("/")
public class MainApplication extends Application {

    @Context ServletContext ctx;

    @Override
    public Set<Class<?>> getClasses() {     
        Set<Class<?>> classes = new HashSet<Class<?>>();
//...
        return classes;
    }
}

web.xml:

<web-app ...>
 <context-param>
  <param-name>environment</param-name>
  <param-value>development</param-value>
 </context-param>
 <filter>
  <filter-name>jersey-filter</filter-name>
  <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
   <init-param>
   <param-name>javax.ws.rs.Application</param-name>
   <param-value>my.MainApplication</param-value>
  </init-param>
</filter>
...
</web-app>

The problem is that I need to get context parameters from it. If there is another way, I would be grateful if somebody gave a hint.


I understand that Context annotation might not be purposed for this. Actually, I do not need ServletContext itself. If only I could get context params from web.xml, I would be absolutely happy.

Here is an example of what I really need:

import java.util.HashSet;
import java.util.Set;

import javax.servlet.ServletContext;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Context;

import org.glassfish.hk2.utilities.binding.AbstractBinder;

public class MainApplication extends Application {

    @Context ServletContext ctx;

    @Override
    public Set<Object> getSingletons() {
        Set<Object> set = new HashSet<Object>();
        final String environment = ctx.getInitParameter("environment");
        //final String environment = ... get context parameter from web xml
        set.add(new AbstractBinder() {

            @Override
            protected void configure() {
                bind(new BaseDataAccess(environment)).to(DataAccess.class);             
            }
        });
        //...
        return set;
    }
}

Thanks.

Upvotes: 18

Views: 26303

Answers (6)

Haruo Kinoshita
Haruo Kinoshita

Reputation: 105

@Context can be made available on ResoureConfig by injecting it as a constructor parameter using @Context. Another way to access it is through an event handler.

Try the below code.

@ApplicationPath("...")
public class MyApplication extends ResourceConfig {
    public MyApplication() {
        register(StartupHandler.class);
    }

    private static class StartupHandler extends  AbstractContainerLifecycleListener {
        @Context
        ServletContext ctx;

        @Override
        public void onStartup(Container container) {
            // You can put code here for initialization. 
        }
    }
// ...

Upvotes: 2

Laurent Mazuel
Laurent Mazuel

Reputation: 3546

Since Jersey 2.5, ServletContext can be injected directly in constructor: https://java.net/jira/browse/JERSEY-2184

public class MyApplication extends ResourceConfig {
    public MyApplication(@Context ServletContext servletContext) {
       // TODO
    }
}

Upvotes: 17

zyexal
zyexal

Reputation: 1579

You can use the ApplicationEventListener interface to get the ServletContext. After initialization has finished, you can 'catch' an ApplicationEvent and use the injected ServletContext to work with.

Works fine with: org.glassfish.jersey : 2.12
For additional versions, pls use comments - i dont know, sry.

Jersey Docs - 20.1.2. Event Listeners

Your MainApplication:

@ApplicationPath("/")
public class MainApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {     
        Set<Class<?>> set = new HashSet<Class<?>>();
        set.add(MainApplicationListener.class);
        return classes;
    }
}

... or alternative MainResourceConfig (I prefer to use this one):

public class MainResourceConfig extends ResourceConfig {
    public MainResourceConfig() {
        register(MainApplicationListener.class);
    }
}

And the ApplicationEventListener:

public class MainApplicationListener implements ApplicationEventListener {

    @Context
    private ServletContext ctx; //not null anymore :)

    @Override
    public void onEvent(ApplicationEvent event) {
        switch (event.getType()) {
            case INITIALIZATION_FINISHED:
            // do whatever you want with your ServletContext ctx
            break;
    }

    @Override
    public RequestEventListener onRequest(RequestEvent requestEvent) {
        return null;
    }

}

Upvotes: 1

Sergey Petrunin
Sergey Petrunin

Reputation: 261

There is interesting statement in documentation for Jersey version 1.18 for class com.sun.jersey.spi.container.servlet.ServletContainer

The servlet or filter may be configured to have an initialization parameter "com.sun.jersey.config.property.resourceConfigClass" or "javax.ws.rs.Application" and whose value is a fully qualified name of a class that implements ResourceConfig or Application. If the concrete class has a constructor that takes a single parameter of the type Map then the class is instantiated with that constructor and an instance of Map that contains all the initialization parameters is passed as the parameter.

If my understanding is correct the following constructor must be invoced with "an instance of Map that contains all the initialization parameters"

public class ExampleApplication extends Application {
    public ExampleApplication(Map initParams) {
    }
    ...
}

Here is appropriate part of web.xml:

<servlet>
  <servlet-name>Jersey Web Application</servlet-name>
  <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
       <param-name>javax.ws.rs.Application</param-name>
       <param-value>experiment.service.ExampleApplication</param-value>
    </init-param>
</servlet>

But somehow it failed for me with the following message:

SEVERE: Missing dependency for constructor public experiment.service.ExampleApplication(java.util.Map) at parameter index 0

And for current version of Jersey (2.5.1) there are no such statement in documentstion: https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/servlet/ServletContainer.html

Upvotes: 1

user1907906
user1907906

Reputation:

Don't use @Context in your Application but in a Resource class.

@Path("/foos")
public class FooResource {

  @Context
  ServletContext ctx;

  @GET
  public Response getFoos() {
    return Response.ok().build();
  }
}

Upvotes: 0

user987339
user987339

Reputation: 10727

Injection happens when you enter service method. Check if this is a problem.

Upvotes: 1

Related Questions