java - ¿Cómo configurar la aplicación JAX-RS utilizando solo anotaciones(sin web.xml)?
java-ee servlet-3.0 (6)
Como @ Eran-Medan señaló, JBoss EAP 7.1 (nota sin una aplicación web así que no hay servlet, lo estaba haciendo en un proyecto EJB 3.2) Tuve que agregar el atributo "valor" como tal, ya que recibía una excepción de que el atributo de valor fue requerido.
Esto funcionó para mí
@ApplicationPath(value="/*")
public class MyApplication extends Application {
private Set singletons = new HashSet();
public MyApplication() {
singletons.add(new MyService());
}
...
}
Stack Trace
Caused by: java.lang.annotation.IncompleteAnnotationException: javax.ws.rs.ApplicationPath missing element value
at sun.reflect.annotation.AnnotationInvocationHandler.invoke(AnnotationInvocationHandler.java:80)
at com.sun.proxy.$Proxy141.value(Unknown Source)
... 21 more
¿Es posible configurar una aplicación JAX-RS usando solo anotaciones? (usando Servlet 3.0 y JAX-RS Jersey 1.1.0)
Lo intenté y no tuve suerte. El uso de algunos web.xml
parece necesario.
Configuración A (en funcionamiento, pero tiene configuración web.xml)
web.xml
...
<servlet>
<servlet-name>org.foo.rest.MyApplication</servlet-name>
</servlet>
<servlet-mapping>
<servlet-name>org.foo.rest.MyApplication</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
...
Java
@ApplicationPath("/")
public class MyApplication extends Application {
...
}
Configuración B (no funciona, excepción arrojada)
@ApplicationPath("/")
@WebServlet("/*") // <--
public class MyApplication extends Application {
...
}
Este último parece insistir en que la Aplicación será una subclase de Servlet (la excepción no deja dudas)
java.lang.ClassCastException: org.foo.rest.MyApplication cannot be cast to javax.servlet.Servlet
Preguntas
¿Por qué funcionó la definición de web.xml pero la anotación no? ¿Cual es la diferencia?
¿Hay alguna manera de que funcione, por ejemplo, tener una aplicación JAX-RS sin web.xml?
El Capítulo 2 de la JAX-RS: la API de Java ™ para la especificación de servicios web RESTful describe el proceso de publicación de una aplicación JAX-RS en el entorno Servlet (sección 2.3.2 Servlet en la especificación).
Tenga en cuenta que solo se recomienda el entorno Servlet 3 (sección 2.3.2 Servlet, página 6):
Se RECOMIENDA que las implementaciones admitan el mecanismo de pluggabilidad del marco de Servlet 3 para permitir la portabilidad entre contenedores y para aprovechar las facilidades de exploración de clase provistas por el contenedor.
En resumen, si desea utilizar un enfoque no-web.xml, es posible con una implementación personalizada de javax.ws.rs.core.Application que registre los recursos del servicio RESTful con la anotación javax.ws.rs.ApplicationPath .
@ApplicationPath("/rest")
Aunque ha preguntado específicamente sobre Jersey, también puede leer el artículo Implementación de servicios RESTful con JAX-RS y WebSphere 8.5 Liberty Profile en el que describí el proceso de publicación no-web.xml para WebSphere Liberty Profile (con Apache Wink como implementación de JAX-RS).
Las dependencias mencionadas anteriormente no funcionaron para mí. De la guía de usuario de Jersey:
Jersey proporciona dos módulos Servlet. El primer módulo es el módulo Servlet central de Jersey que proporciona el soporte de integración Servlet central y se requiere en cualquier contenedor Servlet 2.5 o superior:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
</dependency>
Para admitir modos de implementación de Servlet 3.x adicionales y un modelo de programación de recursos JAX-RS asíncrono, se requiere un módulo Jersey adicional:
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
El módulo jersey-container-servlet depende del módulo jersey-container-servlet-core, por lo tanto, cuando se utiliza, no es necesario declarar explícitamente la dependencia jersey-container-servlet-core.
https://jersey.github.io/documentation/latest/deployment.html#deployment.servlet.3
Necesita configurar las dependencias correctas en pom.xml
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
Más detalles aquí: Ejemplo de inicio para jax-rs
Parece que todo lo que necesitaba hacer era esto (Servlet 3.0 y superior)
@ApplicationPath("/*")
public class MyApplication extends Application {
...
}
Y aparentemente no se necesitaba ninguna configuración web.xml (probado en Tomcat 7)
** ¡LEA POR FAVOR SI USTED UTILIZA TOMCAT O JETTY! **
La respuesta aceptada sí funciona, pero solo si la aplicación web se implementa en un servidor de aplicaciones como Glassfish o Wildfly, y posiblemente en contenedores servlet con extensiones EE como TomEE. No funciona en contenedores servlet estándar como Tomcat, que estoy seguro que la mayoría de las personas que buscan una solución aquí quieren usar.
Si está utilizando una instalación estándar de Tomcat (o algún otro contenedor de servlets), debe incluir una implementación de REST ya que Tomcat no viene con uno. Si está usando Maven, agregue esto a la sección de dependencies
:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>2.13</version>
</dependency>
...
</dependencies>
Luego solo agrega una clase de configuración de aplicación a tu proyecto. Si no tiene ninguna necesidad de configuración especial aparte de establecer la ruta de contexto para los servicios de resto, la clase puede estar vacía. Una vez que se agrega esta clase, no necesita configurar nada en web.xml
(o tiene uno):
package com.domain.mypackage;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
@ApplicationPath("rest") // set the path to REST web services
public class ApplicationConfig extends Application {}
Después de esto, declarar sus servicios web es sencillo utilizando las anotaciones JAX-RS estándar en sus clases de Java:
package com.domain.mypackage;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.GET;
import javax.ws.rs.MatrixParam;
import javax.ws.rs.Path;
// It''s good practice to include a version number in the path so you can have
// multiple versions deployed at once. That way consumers don''t need to upgrade
// right away if things are working for them.
@Path("calc/1.0")
public class CalculatorV1_0 {
@GET
@Consumes("text/plain")
@Produces("text/plain")
@Path("addTwoNumbers")
public String add(@MatrixParam("firstNumber") int n1, @MatrixParam("secondNumber") int n2) {
return String.valueOf(n1 + n2);
}
}
Esto debería ser todo lo que necesitas. Si su instalación de Tomcat se ejecuta localmente en el puerto 8080 y despliega su archivo WAR en el contexto myContext
, yendo a ...
http://localhost:8080/myContext/rest/calc/1.0/addTwoNumbers;firstNumber=2;secondNumber=3
... debería producir el resultado esperado (5).