Solucionado (ver solução)
Solucionado
(ver solução)
11
respostas

JAXB e JPA Hibernate OneToMany lazy

Bom dia!

Estou utilizando hibernate no desenvolvimento de um web service.

A classe Cliente possui um List de comentarios (OneToMany).

O comportamento esperado é Lazy.

Porém, o serviço está respondendo de forma Eager (não desejado).

Quando fiz um debug, percebi que aparentemente o hibernate age como esperado (Lazy).

Porém, após o retorno da Response, aparentemente JAXB chama o get da Lista de comentários, e acaba fazendo o carregamento (não desejado) da Lista (Eager).

Qual seria a solução para este problema?

Estou utilizando a implementação RestEasy, JBoss AS7.

Obrigado!

insira seu código aqui
11 respostas

Oi Odante, tudo bem ?

Imagino que ele faça isso devido a criação do json, dado que você tem uma lista como atributo ele a preenche automaticamente.

Imagino que possa usar um @Transient da vida para solucionar isso, contudo não sei se vai dar o resultado esperado.

solução!

Boa tarde, Odante! Como vai?

Vc pode aplicar o padrão de projeto DTO (Data Transfer Object). Cria uma classe que vai representar as informações que serão trafegadas e manda uma instância dessa classe para o JAX-B serializar.

Assim fica até melhor pq vc garante desacoplamento entre os dados trafegados e o modelo de dados interno da sua aplicação.

Grande abraço!

Alguém poderia dar um exemplo simples de implementação de um DTO em um contexto REST? Como ficaria a "ligação" do DTO com a persitência? Eu também estou tendo dificuldades na implementação de recursos REST que representam entidades com relacionamentos no banco.

Boa tarde, Fernando! Como vai?

O quem vai ter ligação com a persistência ainda serão as suas classes que representam as tabelas no BD! O que vai acontecer é que no seu recurso, em vez de retornar um objeto da classe que represeta a tabela, vai retornar um objeto DTO! A mudança será algo do tipo, o que era assim:

@Path("/funcionario")
public class FuncionarioResource {
     @GET
     @Path("/{id}")
     public Funcionario getFuncionario(@PathParam("id") Integer idFuncionario) {
          Funcionario funcionario = // busca funcionario
          return funcionario;
     }
}

Passará a ser:

@Path("/funcionario")
public class FuncionarioResource {
     @GET
     @Path("/{id}")
     public FuncionarioDto getFuncionario(@PathParam("id") Integer idFuncionario) {
          Funcionario funcionario = // busca funcionario
          FuncionarioDto funcionarioDto = new FuncionarioDto();
          funcionarioDto.setNome( funcionario.getNome() ); // nesse caso o DTO irá transportar somente o nome do funcionário, mas poderia ser qualquer valor que quisermos.
          return funcionarioDto;
     }
}

Ficou claro, pessoal?

Grande abraço!

Oi Gabriel, obrigado pelo retorno.

Entendi, mas e no post de um recurso? O meu método abaixo receberia um TicketDTO como parâmetro e, dentro do método eu crio um objeto Ticket com os dados do TicketDTO? E o meu dao continua salvando uma entidade normalmente, seria isso?

@POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response adiciona(Ticket ticket) {

        TicketDAO ticketDao = TicketDAO.getInstance();
        ticketDao.saveOrUpdate(ticket);
        URI uri = URI.create("pedidos/" + ticket.getId());
        return Response.created(uri).build();

}

As anotações JAX-B continuam na entidade ou ficam no DTO?

Exato, Fernando! O ideal é que tanto no recebimento dos seus dados como no envio deles tudo seja representado pelo seu DTO e o DAO continuará trabalhando com a classe entidade.

Em relação ao JAX-B, as anotações ficam no DTO.

Mas usar o DTO não vai gerar muita duplicidade de código não? Toda vez gerar tanta duplicidade assim não parece bom para manutenção. Como podemos resolver isso? Qual seria uma boa solução para diminuir ao máximo essa duplicidade? e há alguma outra forma de resolver esse problema?

Rogério, não é duplicidade pq são modelos diferentes! No DTO vai estar somente o que é trafegado externamente à aplicação enquanto a classe que modela uma tabela do BD (nesse caso a classe Cliente) representará o que será trafegado de forma interna à aplicação! Mudar a classe Cliente não implica necessariamente em ter que mudar o DTO e nem mudar o DTO implica em ter que mudar a classe Cliente.

Gabriel, o DTO precisa ser composto de outros objetos DTO? Tipo um FuncionarioDTO ter os campos EnderecoDTO, CidadeDTO, etc...?

Depende, Fernando! Vai depender do problema que vc está querendo resolver! Mas nada te impede de fazer algo assim caso seja necessário!