Posted by Clayton Casteli On August - 1 - 2015 0 Comment

Nesse post vamos mostrar alguns pontos de configuração para usar Jersey com JSON. Os testes serão feitos em um servidor tomcat, porém você pode utilizar um web container de sua preferência ou mesmo um application server.

Para application server weblogic, apenas deve se lembrar de configurar os pacotes na versão que será usada em seus arquivos de configuração.

  1. Configurações minimas em um projeto maven para ter as dependências necessárias para usarmos Jersey;
  2. Jersey Root Resource Classes, Method Resource Classes, Mapeamento web.xml;
  3. JAX-RS Application Model;
  4. Mapear o web.xml com Servlet API 3;
  5. Mapear o web.xml com Servlet API inferior 3;
  6. Exemplo Jersey JSON com Jackson;

Configurações mínimas em um projeto maven para ter as dependências necessárias para usarmos Jersey.

Como vamos fazer a instalação no Tomcat e não temos nenhuma implementação JAX-RS uma duas dependencias abaixo são necessárias. Veja que para servlet API inferior a 3 a dependência deve ser jersey-container-servlet-core e para servlet API 3 jersey-container-servlet.
Em nosso caso vamos utilizar Servlet API 3, porém mostramos abaixo cada dependência para utilização do Jersey e alguns recursos que podem nos ajudar.


<!-- para Servlet API inferior a versao 3 
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
    <version>2.19</version>
</dependency>

-->


<!-- para Servlet API na versao 3 -->
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.19</version>
</dependency>


<!-- Apenas se for usar JAX-RS Client 
<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.19</version>
</dependency>
-->


<!--CDI Inject Suport -->
<dependency>
    <groupId>org.glassfish.jersey.ext.cdi</groupId>
    <artifactId>jersey-cdi1x</artifactId>
    <version>2.19</version>
</dependency>



<!-- Para usar MOXy como JSON provider
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.19</version>
</dependency>
-->


<!-- Java API for JSON - JSON-P
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-processing</artifactId>
    <version>2.19</version>
</dependency>
-->

<!-- Jackson for privider JSON -->
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.19</version>
</dependency>


<!-- Jettison

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jettison</artifactId>
    <version>2.19</version>
</dependency>
-->

<!-- JAXB xml
<dependency>
	<groupId>org.glassfish.jersey.media</groupId>
	<artifactId>jersey-media-jaxb</artifactId>
	<version>2.19</version>
</dependency>
-->


<repositories>
 <repository>
	<id>snapshot-repository.java.net</id>
	<name>Java.net Snapshot Repository for Maven</name>
	<url>https://maven.java.net/content/repositories/snapshots/</url>
	<layout>default</layout>
 </repository>
</repositories>


<!--Caso descarte o uso de web.xml por Servlet API 3 -->
<plugins>    
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <version>2.3</version>
        <configuration>
            <failOnMissingWebXml>false</failOnMissingWebXml>
        </configuration>
    </plugin>    
</plugins>

Jersey Root Resource Classes, Method Resource Classes, Mapeamento web.xml

Antes de mostrar-mos um exemplo de Jersey com JSON, falaremos um pouco sobre Root Resource Classes, Method Resource Classes, anotações utilizadas e mapeamento no web.xml caso necessário.

Root resource classes são POJOs (Plain Old Java Objects) que são anotadas com @Path para indicarem o caminho relativo de acesso a classe de resource. Uma classe de resource pode ter seus resources métodos anotados com @GET, @PUT, @POST, @DELETE.

Um método de resource pode ter sub path, ou seja, podendo tembém ser annotado com @Path, isso permite que dentro de uma classe de Resource a adição ao caminho seja feita para indicar uma método especifico.

No exemplo abaixo temos /myresource como path da classe de resource e um sub path que é uma variável chamada username. A variável username e lida pelo método e retornada. O que possibilita a leitura é a anotação @PathParam("username") que carrega o valor da variável username em userName na chamada ao método.

@Path("/myresource")
public class MyResource {    
   
    @GET
    @Produces("text/plain")
    @Path("{username}")
    public String getName(@PathParam("username") String userName) {
        return "Hi " + userName;
    }


    @GET
    @Consumes("text/plain")
    @Path("consumidor/{username}")
    public void setIt(@PathParam("username") String userName) {
        
    	System.out.println("Hi " + userName + " !");
    }

}

O acesso aos métodos de resource mostrados acima se dão pelo caminho abaixo.

	Produces	
	 "http://IPServer:Port/AppContext/webresources/myresource/algum_nome"
	
	Consumes	
	"http://IPServer:Port/AppContext/webresources/myresource/consumidor/algum_nome"

Veja que apareceu ao caminho o path "webresources" que vamos explicar mais a frente.

Em nosso exemplo a anotação @Produces e usada para especificar a representação do MIME media types que o resource ira retornar ao cliente. No exemplo esta como "text/plain" porém outras como "application/xml", "application/json" podem ser retornadas, ou mesmo priorizadas em um mesmo método.

A anotação @Produces("text/plain") pode ser usada em uma classe, isso significa que qualquer método não anotado na Classe de resource herdara o produces e sua representação de MIME media type.

A anotação @Consumes é usada para especificar a representação de MIME media types do resource que será o consumidor, ou seja, estamos usando a anotação Produces para saída de dados para o cliente e a anotação Consumes para a entrada de dados.

Existe muitas outras anotaçoes que possibilitam injeção em EJB's, ManageBaen, tratamentos de dados recebidos via post. Para analisar outras anotações uteis a documentação pode ser consultada no link Jersey. Esse post visa apenas mostrar a configuração para uma aplicação JSON usando Jersey.

JAX-RS Application Model

Um pouco acima nesse post falamos sobre o caminho de acesso ao nosso exemplo, no caminho de acesso apareceu uma parte do relative path chamado "webresources". Esse caminho se deve ao JAX-RS Application Model.
O JAX-RS prove uma class abstrata chamada Application usada para declarar as root resources, instancias singletons ou mesmo outras classes necessárias para inserirmos tratamentos de outros recursos como o JSON que falaremos mais a frente.

Essas classe são identificadas no web.xml, ou quando utilizado Servlet API 3 podemos desconsiderar o uso do web.xml e utilizarar a anotação, @ApplicationPath("webresources"), em uma das classes abaixo, onde "webresources" será parte do caminho de acesso ao métodos de resource da aplicação.

package br.com.jersey;

//Pode estender a class Application e identificar a classe de reosurce
//@ApplicationPath("webresources")
public class MyApplication extends Application {
    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> s = new HashSet<Class<?>>();
        s.add(MyResource.class);
        return s;
    }
}

//Pode estender a class ResourceConfig que permite simplificar a forma de registrar um resource, nesse caso uso de scan para procurar
// as classes de reosurces nos pacotes especificados
//@ApplicationPath("webresources")
public class MyApplication extends ResourceConfig {
    public MyApplication() {
        packages("br.com.jersey, br.com");
    }
}

Mapear o web.xml com Servlet API 3

Caso use Servlet API 3 tudo que precisa fazer para ter um serviço Jersey Rest executando é anotar uma das classes de Application como mostramos acima com @ApplicationPath("webresources"). Porém se preferir indicar a sub classe, no exemplo chamada MyApplication, no web.xml ou mesmo deixar o Jersey fazer uma cunfiguração dinamica, quando não temos uma sub-classe Application, segue exemplos abaixo.

Mapeamento da sub classe

<web-app>
    <servlet>
        <servlet-name>br.com.jersey.MyApplication</servlet-name>
    </servlet>
    ...
    <servlet-mapping>
        <servlet-name>br.com.jersey.MyApplication</servlet-name>
        <url-pattern>/webresources</url-pattern>
    </servlet-mapping>
    ...
</web-app>

Mapeamento dinamico sem sub classe

<web-app>
<servlet>
        <servlet-name>javax.ws.rs.core.Application</servlet-name>
    </servlet>
 
<servlet-mapping>
     <servlet-name>javax.ws.rs.core.Application</servlet-name>
     <url-pattern>/webresources/*</url-pattern>
</servlet-mapping>
</web-app>

Mapear o web.xml com Servlet API inferior 3

No caso de Servlet API ser inferior a 3 ai precisamos fazer o mapeamento via web.xml.

Alguns exemplos serão mostrados abaixo com sevelt, porém poder ser feitos igualmente com filter. Para mais detalhes veja link Jersey web.xml https://jersey.java.net/documentation/latest/deployment.html

Podemos mapear a sub class MyApplication

<servlet>
        <servlet-name>MyApplication</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
    		<param-name>javax.ws.rs.Application</param-name>
    		<param-value>br.com.jersey.MyApplication</param-value>
	</init-param>
    </servlet>  
    <servlet-mapping>
        <servlet-name>MyApplication</servlet-name>
        <url-pattern>/webresources/*</url-pattern>
    </servlet-mapping>
</web-app>

Podemos mapear package scanning

<servlet>
        <servlet-name>MyApplication</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
    		<param-name>jersey.config.server.provider.packages</param-name>
    	<param-value>
	        br.com.jersey,org.br
    	</param-value>
	</init-param>
	<init-param>
	    <param-name>jersey.config.server.provider.scanning.recursive</param-name>
	    <param-value>false</param-value>
	</init-param>
    </servlet>  
    <servlet-mapping>
        <servlet-name>MyApplication</servlet-name>
        <url-pattern>/webresources/*</url-pattern>
    </servlet-mapping>
</web-app>

Podemos mapear as classes de resource

<servlet>
        <servlet-name>MyApplication</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
    		<param-name>jersey.config.server.provider.classnames</param-name>
	    	<param-value>
        		 br.com.jersey.MyResource/*, pode inserior outros*/        		
	    	</param-value>
	</init-param>
    </servlet>  
    <servlet-mapping>
        <servlet-name>MyApplication</servlet-name>
        <url-pattern>/webresources/*</url-pattern>
    </servlet-mapping>
</web-app>

Exemplo Jersey JSON com Jackson

Um exemplo simples do uso de Jersey com JSON Jeckson será mostrado baixo. O exemplo mostra o retorno de uma lista de pessoas, @Produces, e um consumidor para inserir uma nova pessoa ao repositório de dados.

Para esse exemplo como explicado acima, não vamos usar web.xml e sim a anotação @ApplicationPath para registrar nossa classe de Application.

A sub classe MyApplication não requer a configuração de web.xml, pelo fato de estarmos usando @ApplicationPath. Na classe MyApplication registramos a classe "JacksonFeature" para uso do Jackson e o scan de pacotes em "br.com.jersey" para as classes de resources.



package br.com.jersey;

import javax.ws.rs.ApplicationPath;

import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;

/**
 * @author clayton
 *
 */
@ApplicationPath("webresources")
public class MyApplication extends ResourceConfig {
  public MyApplication() {
      packages("br.com.jersey")
      .register(JacksonFeature.class);
  }
}

Para a classe de resource dois métodos foram criados, uma para listar pessoas e outro salvar/incluir novas pessoas.



package br.com.jersey;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;



import br.com.jersey.util.DBPessoa;

/** URI path "/myresource"
 */
@Path("/myresource")
public class MyResource {
	

   DBPessoa dbPessoa = DBPessoa.intance();  
   
    @GET
    @Produces({MediaType.APPLICATION_JSON})
    @Path("listaPessoa")
    public List<Pessoa> listaPessoa() {  
    	
        return dbPessoa.getLista();
    }  
    
    
    @POST
    @Produces({MediaType.APPLICATION_JSON})
    @Path("salvaPessoa")
    public void salvaPessoa(Pessoa pessoa) {    	
    	    	
       dbPessoa.add(pessoa);
    }
   
    
}


A classe pessoa apenas um POJO com as propriedades de pessoa, essa classe será retornada em formato JSON.


public class Pessoa {
	
	
	private String nome;
	private String email;
	private Date nascimento;
	private Date dataCorrente;
	private int idade; 

	public Pessoa() {
		
	}

	public Pessoa(String nome, String email, Date nascimento,
			Date dataCorrente, int idade) {
		super();
		this.nome = nome;
		this.email = email;
		this.nascimento = nascimento;
		this.dataCorrente = dataCorrente;
		this.idade = idade;
	}

	public String getNome() {
		return nome;
	}

	public void setNome(String nome) {
		this.nome = nome;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public Date getNascimento() {
		return nascimento;
	}

	public void setNascimento(Date nascimento) {
		this.nascimento = nascimento;
	}

	public Date getDataCorrente() {
		return dataCorrente;
	}

	public void setDataCorrente(Date dataCorrente) {
		this.dataCorrente = dataCorrente;
	}

	public int getIdade() {
		return idade;
	}

	public void setIdade(int idade) {
		this.idade = idade;
	}
		

}

A classe DBPessoa é apenas a representação do repositório de dados para os testes.



package br.com.jersey.util;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import br.com.jersey.Pessoa;

public class DBPessoa {

	private List<Pessoa> lista = new ArrayList<Pessoa>();
	static private DBPessoa DB = new DBPessoa();

	/**
	 * 
	 */
	private DBPessoa() {
		
		lista = new ArrayList<Pessoa>();

		Pessoa p = null;
		for (int i = 0; i < 10; i++) {
			p = new Pessoa("Clayton", "email@gmail.com", new Date(),
					new Date(), 25);

			lista.add(p);

		}

		

	}

	static public DBPessoa intance() {

		if (DB == null) {

			DB = new DBPessoa();
		}

		return DB;

	}

	public List<Pessoa> getLista() {
		return lista;
	}

	public void setLista(List<Pessoa> lista) {
		this.lista = lista;
	}
	
	public void add(Pessoa p) {
		
		this.lista.add(p);
	}
	

}


Para executar teste do retorno da lista de dados em o servidor Tomcat o caminho abaixo pode ser utilizado.

http://IP:PORT/AppContext/webresources/myresource/listaPessoa

About the author

Clayton Casteli

Atua com desenvolvimento de software, J2EE, C/C++, IBM BPM. É entusiasta de novas tecnologias, principalmente open source. Formado em Engenharia da Computação pela PUCCAMP-SP, Pós-Graduado pela UNICAMP em Engenharia de Software com enfase em SOA e Pós-Graduado em Business Intelligence pelo IBTA.

Be Sociable, Share!

Protected by WP Anti Spam