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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
 
@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

No comments: