Monday, May 27, 2013

RESTEasy: Erro ao retornar List em XML - Could not find MessageBodyWriter for response object of type: xxx application/xml

Outro dia me deparei com uma exception gerada pelo RESTEasy, o erro era: Could not find MessageBodyWriter for response object of type: java.util.ArrayList of media type: application/xml.

No meu cenário, o problema ocorria ao utilizar o componente Response do RESTEasy como retorno do método. Pra ficar mais claro a seguir um exemplo de código simulando o erro, no caso a entidade e o endpoint do RESTEasy:
@Entity
@XmlRootElement
public class Carro {

  @Id
  private Long id;

  @NotNull
  private String renavam;

  private String placa;

  @NotNull
  @ManyToOne
  private Modelo modelo;

  //...

}


@Path("/carros")
public class CarroEndpoint {
  ...

  @GET
  @Path("/{id:[0-9][0-9]*}")
  @Produces("application/xml")
  public Response findById(@PathParam("id") Long id) {
    try {
      Carro c = service.findById(id); 
      return Response.ok(c).build();
    } catch (NoResultException nrex) {
      return Response.status(Status.NOT_FOUND).build(); //404
    }
  }

  @GET
  @Produces("application/xml")
  public List<Carro> listAll() {
    return service.listAll();
  }

  @GET
  @Path("/{modelo}")
  @Produces("application/xml")
  public Response listByModelo(@PathParam("modelo") String descModelo) {
    Modelo m = service.findModeloByDescricao(descModelo);
    if (m == null) {
      return Response.status(Status.NOT_FOUND).build();
    }

    List<Carro> carros = service.findByModelo(m);
    return Response.ok(carros).build(); //o problema ocorre aqui
  }

}

Os  métodos findById e listAll funcionam corretamente, ambos devolvem o XML representando os dados dos carros encontrados de acordo com a consulta. Note o retorno desses dois métodos: a entidade Carro e uma lista de Carros.

A exception ocorre no terceiro método, no listByModelo, aonde faço uso da Response (componente do RESTEasy). Nesse caso o RESTEasy não consegue transformar o ArrayList em XML. A mesma situação acontece com outra coleção, por exemplo HashSet.

Pra resolver o problema, eu utilizei o GenericEntity para "tipar" a lista, de forma que o RESTEasy possa realizar a transformação em XML. A mesma abordagem funciona com HashSet. A seguir a nova versão de listByModelo:
  ...

  @GET
  @Path("/{modelo}")
  @Produces("application/xml")
  public Response listByModelo(@PathParam("modelo") String descModelo) {
    Modelo m = service.findModeloByDescricao(descModelo);
    if (m == null) {
      return Response.status(Status.NOT_FOUND).build();
    }

    List<Carro> carros = service.findByModelo(m);
    GenericEntity<List<Carro>> entity = new GenericEntity<List<Carro>>(carros);
    return Response.ok(entity).build(); //ok
  }
  ...

A versão do RESTEasy utilizada foi a 2.3.6.Final.

[]s
http://twitter.com/edermag
http://www.yaw.com.br

Wednesday, May 15, 2013

Configurar conexões remotas para o MongoDB no Ubuntu

Uma vez que o mongoDB já foi instalado no Ubuntu, é muito simples habilitar conexões remotas para o serviço. Basta indicar o uso do ip e porta no arquivo de configurações do mongoDB, mongodb.conf. (Acesse c/ super-usuário - sudo)

$ sudo gedit /etc/mongodb.conf

Inclua esses dois parametros:
bind_ip = 0.0.0.0
port = 27017

A propriedade port já vem comentada na instalação padrão.

Importante: nesse post não levo em consideração aspectos de segurança e restrição de acesso ao mongoDB.

Você pode acessar o mongoDB de outra máquina, indicando o ip dá maquina aonde o banco foi instalado. Esse acesso pode ocorrer via terminal ou com um ferramenta GUI para o MongoDB, como o UMongo (app p/ Linux).

É isso!

http://twitter.com/edermag
http://www.yaw.com.br

Monday, May 06, 2013

Openshift, como fazer o deploy de um war pronto no Tomcat

No Openshift é possível trabalhar com diversas tecnologias, como: Java, PHP, Ruby, Node.js e até Perl. Além das linguagens, a plataforma cloud computing da Red Hat (PaaS) também oferece suporte a uma série de serviços complementares, como gestor de build (Maven p/ Java), ferramenta para integração contínua (Jenkins), controlador e repositório de fontes (Git).

O Openshift agrega esses serviços/ferramentas a plataforma com objetivo de ampliar a capacidade de desenvolvimento. Dessa forma além de usar o hosting em nuvem, você pode contar com uma melhor gestão de build, baseado na execução de testes, com a possibilidade de commits em repositórios segmentados.

Mas é possível ignorar esses serviços, e fazer o deploy da aplicação "pronta" no Openshift. Pronto no sentindo de que o artefato foi gerado local, sem interferência do Openshift. Isso pode ser interessante em situações pontuais, como demos ou provas de conceito.

Nesse post demonstro como realizar o deploy de uma aplicação Java web (um war), no Tomcat, sem utilizar o Maven, Jenkins e Git*.
*Na verdade não colocamos os fontes no Git, mas o utilizamos para armazenar o war da aplicação.

1 - Crie a aplicação no Openshift, e faça o clone local do repositório Git. Note que dentro do diretório principal, no repositório local, existe a subpasta webapps.

2 - Acesse o código fonte da aplicação para gerar o artefato web, o war. Se preferir utilize o Maven, rodando local, para controlar o build gerar o war.

3 - Copie o arquivo war para a pasta webapps, dentro do repositório Git local:
$ cp aplicacao.war  [caminho do repositorio]/webapps/

4 - Coloque o arquivo no repositório local e master. Execute o fluxo add / commit e push do Git:
$ cd  [caminho do repositorio]/webapps/

$ git add aplicacao.war
$ git commit -m "seu comentario"
$ git push origin master

Em caso de um redeploy, uma nova versão, antes do passo 3, remova o arquivo war atual:
$ git rm aplicacao.war 

Pronto, com esses passos é possível publicar uma aplicação "pronta" no Openshift.

http://twitter.com/edermag
http://www.yaw.com.br