Article updated on

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

Tomcat 7 WAR file here

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)

img/1/107/1.png

  • Cuando hayas desplegado la aplicación puedes arrancar el TestClient.java as como una aplicación Java. En eclipse el resultado sería:

img/1/107/2.png

 

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.