real - javax.servlet.servletcontext jar
Obtener ServletContext en la aplicaciĆ³n (6)
¿Podría posiblemente explicar cómo puedo obtener la instancia ServletContext
en la subclase de mi Application
? ¿Es posible? He intentado hacerlo como en el siguiente fragmento de código pero parece que no funciona, el ctx
no está configurado:
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>
El problema es que necesito obtener parámetros de contexto de él. Si hay otra forma, agradecería que alguien me diera una pista.
Entiendo que la anotación de Context
podría no estar diseñada para esto. En realidad, no necesito ServletContext
. Si solo pudiera obtener parámetros de contexto de web.xml, estaría absolutamente feliz.
Aquí hay un ejemplo de lo que realmente necesito:
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;
}
}
Gracias.
Desde Jersey 2.5, ServletContext se puede inyectar directamente en el constructor: https://java.net/jira/browse/JERSEY-2184
public class MyApplication extends ResourceConfig {
public MyApplication(@Context ServletContext servletContext) {
// TODO
}
}
Hay una declaración interesante en la documentación de la versión 1.18 de Jersey para la clase com.sun.jersey.spi.container.servlet.ServletContainer
El servlet o filtro puede configurarse para tener un parámetro de inicialización "com.sun.jersey.config.property.resourceConfigClass" o "javax.ws.rs.Application" y cuyo valor es un nombre completo de una clase que implementa ResourceConfig o Solicitud. Si la clase concreta tiene un constructor que toma un solo parámetro del tipo Mapa, entonces la clase se crea una instancia con ese constructor y una instancia de Mapa que contiene todos los parámetros de inicialización se pasa como parámetro.
Si mi entendimiento es correcto, el siguiente constructor debe ser invocado con "una instancia de Map que contenga todos los parámetros de inicialización"
public class ExampleApplication extends Application {
public ExampleApplication(Map initParams) {
}
...
}
Aquí está la parte apropiada de 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>
Pero de alguna manera me falló el siguiente mensaje:
GRAVE: Falta la dependencia para el constructor public experimental.service.ExampleApplication (java.util.Map) en el índice de parámetro 0
Y para la versión actual de Jersey (2.5.1) no hay tal declaración en documentstion: https://jersey.java.net/apidocs/latest/jersey/org/glassfish/jersey/servlet/ServletContainer.html
La inyección ocurre cuando usted ingresa el método de servicio. Compruebe si esto es un problema.
No use @Context
en su Application
sino en una clase de recursos.
@Path("/foos")
public class FooResource {
@Context
ServletContext ctx;
@GET
public Response getFoos() {
return Response.ok().build();
}
}
Puede usar la interfaz ApplicationEventListener
para obtener el ServletContext
. Una vez finalizada la inicialización, puede "capturar" un ApplicationEvent
y usar el ServletContext
inyectado para trabajar.
Funciona bien con: org.glassfish.jersey: 2.12
Para versiones adicionales, los pls usan comentarios - no sé, sry.
Jersey Docs - 20.1.2. Oyentes del evento
Su MainApplication
:
@ApplicationPath("/")
public class MainApplication extends Application {
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> set = new HashSet<Class<?>>();
set.add(MainApplicationListener.class);
return classes;
}
}
... o MainResourceConfig
alternativo (prefiero usar este):
public class MainResourceConfig extends ResourceConfig {
public MainResourceConfig() {
register(MainApplicationListener.class);
}
}
Y el 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;
}
}
@Context
puede estar disponible en ResoureConfig
inyectándolo como un parámetro de constructor usando @Context
. Otra forma de acceder a él es a través de un controlador de eventos .
Pruebe el siguiente código.
@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.
}
}
// ...