Uma ótima apresentação sobre REST me fez querer escrever um pouco sobre. Mais especificamente sobre o RESTEasy, implemetação certificada JAX-RS da JBoss. No projeto que fiz para certificação JBoss Certified SOA Developer o usei bastante e quero falar de algumas interessantes funcionalidades dele. Primeiro algumas considerações sobre REST:
- RESTEasy é um framework para criação de RESTful Web Services, o que em algum senso já é uma desvirtuação de REST (tal como Roy Fielding definiu), que trata de recursos. O que tem haver um serviço RESTful que loga o usuário? (O que aliás abre uma sedutora brecha para quebrar outro conceito REST: o de statelessness) De agora em diante irei usar REST e RESTful Web Services indistintamente.
- REST não é uma alternativa a SOA! Na verdade podemos usar REST para implementar SOA com WOA. Confuso? REST é uma alternativa ao WS-*, podendo ser usado no lugar dele para implementar SOA. A implementação RESTful de SOA é chamada WOA, ou ROA (veja a página de TLAs), que é um subconjunto de SOA.
JAXB binding
RESTEasy possui suporte a marshalling/unmarshalling de classes usando JAXB. Sou péssimo para dar exemplos mas vamos lá…:
@Path("/") public class Servico { @GET @Path("/tempo") @Produces("text/xml") public Tempo getTempo() { return new Tempo("Parcialmente nublado", 20.3); } @POST @Path("/literal") @Consumes("text/xml") public void setTempo(Tempo tempo) { System.out.format("Descrição: %s%n", tempo.getDescricao()); System.out.format("Temperatura: %d%n", tempo.getTemperatura()); } } // classe anotada com JAXB @XmlRootElement class Tempo { private String descricao; private Double temperatura; public Tempo() {} public Tempo(String nome, Double preco) { this.descricao = nome; this.temperatura = preco; } public String getDescricao() { return descricao; } public void setDescricao(String nome) { this.descricao = nome; } public Double getTemperatura() { return temperatura; } public void setTemperatura(Double preco) { this.temperatura = preco; } }
Na invocação de getTempo() RESTEasy vai ver que o tipo de retorno é o objeto Tempo e que ele está anotado com @XmlRootElement e vai fazer um marshalling dele. A anotação @Produces(“text/xml”) diz que a representação gerada deve ser XML. Quer que seja em JSON? Basta mudar para @Produces(“application/json”)!
Do mesmo jeito funciona o setTempo(). O parâmetro passados sem nenhuma anotação é interpretado como o corpo da requisição HTTP, que no caso é um objeto.
RESTEasy Client
Algo muito interessante que não é da especificação JAX-RS é o suporte a clients. Esses clients são proxies que transformam invocações Java em requisições HTTP. Para isso devemos criar uma interface com as mesmas assinaturas do nosso serviço e anotá-las:
public class Main { static { // precisa ser chamo uma única vez para registrar providers RESTEasy, scanear classes, etc RegisterBuiltin.register(ResteasyProviderFactory.getInstance()); // precisa ser chamado uma única vez para } public static void main(String args[]) { IServico client = ProxyFactory.create(IServico.class, "http://localhost:8080/<Context>"); Tempo tempo = client.getTempo(); tempo.setTemperatura(tempo.getTemperatura() + 5.0); client.setTempo(tempo); } } interface IServico { @GET @Path("/tempo") @Produces("text/xml") public abstract Tempo getTempo(); @POST @Path("/literal") @Consumes("text/xml") public abstract void setTempo(Tempo tempo); } // classe anotada com JAXB @XmlRootElement class Tempo { private String descricao; private Double temperatura; public Tempo() {} public Tempo(String nome, Double preco) { this.descricao = nome; this.temperatura = preco; } public String getDescricao() { return descricao; } public void setDescricao(String nome) { this.descricao = nome; } public Double getTemperatura() { return temperatura; } public void setTemperatura(Double preco) { this.temperatura = preco; } }
Agora você deve ver no console:
Descrição: Parcialmente nublado Temperatura: 34.000000
Precisamos a classe Tempo também apenas porque estamos usando JAXB. Tudo transparente, muito fácil agora fazer teste unitários de serviços RESTful!



