Ejemplo con Jersey 2 Cliente y Servidor y Generar documentación con Enunciate
Este ejemplo usa Jersey 2.25 y Maven.
Características:
- Ejemplo Cliente y Servidor con GET y POST
- Ejemplo con Validación por anotaciones.
- Documentación automáticamente generada con Enunciate que incluye el plugin de Swagger.
- Proyecto Maven sin Spring. Sólo usa la librería Jackson para el parseo de JSON.
1 - Descarga el War y los fuentes
Sources and Maven project here
2 - Descarga el War y Prueba la Aplicación
Cuando hayas desplegado el war prueba los siguientes enlaces. (Con el tomcat encendido mueve el WAR a la carpeta webapps)
- http://localhost:8080/TestJersey2/ URL principal con algunos enlaces.
- http://localhost:8080/TestJersey2/docs Para ver la documentación automáticamente generada con Enunciate.
- Cuando hayas desplegado la aplicación puedes arrancar el TestClient.java as como una aplicación Java. En eclipse el resultado sería:
TestClient.java
package com.test.ws.client; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.Entity; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.MediaType; import org.glassfish.jersey.jackson.JacksonFeature; import com.test.ws.view.RequestObj; import com.test.ws.view.ResponseObj; public class TestClient { public static void main( String[] args ) { RequestObj requestObj = new RequestObj(); requestObj.setSinger("Rammstein"); requestObj.setTitle("Stripped"); Client client = ClientBuilder.newBuilder() .register(JacksonFeature.class) .build(); //WS text get WebTarget target = client.target("http://localhost:8080/TestJersey2/rest/").path("test/get"); String res = target.request().get().readEntity(String.class); System.out.println(res); //WS JSON get WebTarget target2 = client.target("http://localhost:8080/TestJersey2/rest/").path("test/get"); String res2 = target2.request(MediaType.APPLICATION_JSON).get().readEntity(String.class); System.out.println(res2); //WS sending and receiving a String by post String req = "{\"title\":\"Stripped\", \"singer\":\"Rammstein\"}";// a valid json WebTarget target3 = client.target("http://localhost:8080/TestJersey2/rest/").path("test/validate"); String res3 = target3.request().post(Entity.entity(req, MediaType.APPLICATION_JSON), String.class); System.out.println(res3); //WS text getsending and receiving objects WebTarget target4 = client.target("http://localhost:8080/TestJersey2/rest/").path("test/validate"); ResponseObj responseObj = target4.request(MediaType.APPLICATION_JSON).post(Entity.entity(requestObj, MediaType.APPLICATION_JSON)).readEntity(ResponseObj.class); System.out.println(responseObj.getResult() + "--" + responseObj.getRetorno() + "--" + responseObj.getError()); } }
TestServer.java
package com.test.ws.rest; import javax.validation.Valid; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.test.ws.view.RequestObj; import com.test.ws.view.ResponseObj; /** * * Server tests * * @author juan * */ @Path("/test") public class TestServer { /** * This method return a hello World * * @return */ @GET public String inicio() { return "Hello World!"; } /** * This method return a hello World * * @return */ @GET @Path("/get") public String hello() { return "Hello World !! - Jersey 2"; } /** * * This method produces a JSON * * @return */ @GET @Path("/get") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public RequestObj getTrackInJSON() { RequestObj requestObj = new RequestObj(); requestObj.setTitle("Enter Sandman"); requestObj.setSinger("Metallica"); return requestObj; } /** * * This method uses the final url part as parameter * * @param id * @param requestObj * @return */ @POST @Path("/post-id/{id}") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON) public ResponseObj getID(@PathParam("id") int id, RequestObj requestObj) { ResponseObj rt = new ResponseObj(); rt.setResult("OK"); rt.setRetorno(Response.Status.OK.getStatusCode() +" OK ->" + id); return rt; } /** * * Test for the PUT * * @param obj * @return */ @PUT @Path("/put") @Consumes(MediaType.APPLICATION_JSON) @Produces(MediaType.TEXT_HTML) public Response objectToLine(String obj) { return Response.status(201).entity("response" + obj).build(); } /** * * Validated Test * * @param requestObj * @return */ @POST @Path("/validate") @Consumes(MediaType.APPLICATION_JSON) public Response validateField(@Valid RequestObj requestObj) { ResponseObj rt = new ResponseObj(); ObjectMapper mapper = new ObjectMapper(); String json = ""; try { json = mapper.writeValueAsString(rt); } catch (JsonProcessingException e) { e.printStackTrace(); } return Response.status(Response.Status.ACCEPTED).entity(json).build(); } }
ConstraintViolationMapper.java
Cuando se producen errores de validación este método se llama.
package com.test.ws.rest; import java.util.Set; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.test.ws.view.ResponseObj; /** * Generic mapper for validations * * @author jcgonzalez.com * */ @Provider public class ConstraintViolationMapper implements ExceptionMapper<ConstraintViolationException> { @Override public Response toResponse(ConstraintViolationException ex) { String msg = " Not valid request "; Set<ConstraintViolation<?>> set = ex.getConstraintViolations(); for (ConstraintViolation<?> cv : set) { msg += "--" + cv.getPropertyPath() + " " + cv.getMessage() + "--"; } ResponseObj rt = new ResponseObj(); rt.setResult("ERROR"); rt.setError(Response.Status.BAD_REQUEST.getStatusCode() + msg); ObjectMapper mapper = new ObjectMapper(); String json = ""; try { json = mapper.writeValueAsString(rt); } catch (JsonProcessingException e) { e.printStackTrace(); } return Response.status(Response.Status.BAD_REQUEST).entity(json).type(MediaType.APPLICATION_JSON).build(); } }
RequestObj.java
package com.test.ws.view; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class RequestObj { @NotNull(message="can't be empty") @Size(min = 0, max = 20, message="20 chars. max.") private String title; @NotNull(message="can't be empty") @Size(min = 0, max = 20, message="20 chars. max.") private String singer; /** * Documentation test * @return */ public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getSinger() { return singer; } public void setSinger(String singer) { this.singer = singer; } @Override public String toString() { return "RequestObj [title=" + title + ", singer=" + singer + "]"; } }
GenericException.java
Cuando se produce en una excepción genérica se llama a este método para que devuelva un JSON de error.
package com.test.ws.rest; import javax.ws.rs.Path; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.test.ws.view.ResponseObj; @Path("/") /** * * Generic Exception error is parsed into a JSON * * @author juan * */ public class GenericException implements javax.ws.rs.ext.ExceptionMapper<Exception> { @Override public Response toResponse(Exception error) { Response response; if (error instanceof WebApplicationException) { WebApplicationException webEx = (WebApplicationException) error; response = webEx.getResponse(); webEx.getResponse().getStatus(); ResponseObj rt = new ResponseObj(); rt.setResult("ERROR"); rt.setError(webEx.getResponse().getStatus() +" " + error.getMessage()); ObjectMapper mapper = new ObjectMapper(); String json = ""; try { json = mapper.writeValueAsString(rt); } catch (JsonProcessingException e) { e.printStackTrace(); } return Response.status(webEx.getResponse().getStatus()) .entity(json) .type(MediaType.APPLICATION_JSON) .build(); } response = Response.status(Response.Status.INTERNAL_SERVER_ERROR) .entity("Internal error").type("text/plain").build(); return response; } }
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0"> <display-name>Servlet 3.0 Web Application</display-name> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>jersey-serlvet</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>com.test.ws.rest</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey-serlvet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.howtodoinjava.jersey</groupId> <artifactId>TestJersey2</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <repositories> <repository> <id>maven2-repository.java.net</id> <name>Java.net Repository for Maven</name> <url>http://download.java.net/maven/2/</url> <layout>default</layout> </repository> </repositories> <properties> <jersey2.version>2.25</jersey2.version> <jaxrs.version>2.0.1</jaxrs.version> <tomcat.version>7.0.69</tomcat.version> <enunciate.version>2.8.0</enunciate.version> <log4j.version>1.2.17</log4j.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <!-- JAX-RS --> <dependency> <groupId>javax.ws.rs</groupId> <artifactId>javax.ws.rs-api</artifactId> <version>${jaxrs.version}</version> </dependency> <!-- Jersey Client--> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>${jersey2.version}</version> </dependency> <!-- Jersey Server--> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>${jersey2.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> <version>${jersey2.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId> <version>${jersey2.version}</version> </dependency> <!-- Jersey Validation --> <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-bean-validation</artifactId> <version>${jersey2.version}</version> </dependency> <!-- JSON library --> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-jackson</artifactId> <version>${jersey2.version}</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-servlet-api</artifactId> <version>${tomcat.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>TestJersey2</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.0</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>com.webcohesion.enunciate</groupId> <artifactId>enunciate-maven-plugin</artifactId> <version>2.8.0</version> <configuration> <docsDir>${project.build.directory}/TestJersey2/docs</docsDir> </configuration> <executions> <execution> <goals> <goal>assemble</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Notas
- El archivo WAR para funcionar requiere Tomcat 7 o superior y la JRE 1.7 o superior.