Problema GSon

Pessoal,

Estou desenvolvendo uma aplicação Web com o Jersey e o GSon.
Até agora estava funcionando lindamente, mas do nada, começou me retornar um erro ao tentar acessar o método (Eu já estava acessando esse método).

Jan 03, 2013 5:17:52 PM com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException SEVERE: The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container java.lang.StackOverflowError
Alguém saberia me dizer o que pode ser?
Já tentei refazer o build path umas 20 vezes e nada.

Agradeço desde já por qualquer ajuda!

Você não mostrou o código das classes que está serializando em JSON, mas esse StackOverflow ai provavelmente é porque você deve ter algum ciclo na sua composição. Por exemplo:

[code]public class Foo {
private Bar bar;
}

public class Bar {
private List foos;
}[/code]
Você tem uma lista de Foo dentro de Bar. Quando tenta serializar um Bar, ele tenta pegar os Foos, mas cada Foo tem um Bar, que tem uma lista de Foos entendeu? Entra em uma cadeia de chamadas infinitas, por isso o Stack Overflow!!! Verifique se é isso.

Lembrando que se eu tentar acessar o método abaixo ele funciona normalmente:

@GET @Path("/listarNormal") @Produces("application/json") public List<Categoria> listAll() { categoriaDAO.beginTransaction(); List<Categoria> categoria = categoriaDAO.findAll(); categoriaDAO.closeTransaction(); return categoria; }
Agora se eu tento acessar o método abaixo ele gera o erro descrito anteriomente, e a única coisa que muda é que ele tenta converter o resultado para GSon.

@GET @Path("/listar") @Produces("application/json") public String androidListarTodos() { return new Gson().toJson(listAll()); }

Antes estava funcionando tudo normalmente. :?

[quote=davidbuzatto]Você não mostrou o código das classes que está serializando em JSON, mas esse StackOverflow ai provavelmente é porque você deve ter algum ciclo na sua composição. Por exemplo:

[code]public class Foo {
private Bar bar;
}

public class Bar {
private List foos;
}[/code]
Você tem uma lista de Foo dentro de Bar. Quando tenta serializar um Bar, ele tenta pegar os Foos, mas cada Foo tem um Bar, que tem uma lista de Foos entendeu? Entra em uma cadeia de chamadas infinitas, por isso o Stack Overflow!!! Verifique se é isso.[/quote]

Então, eu tenho isso sim! Mas é por conta do hibernateJPA.
Por exemplo, na minha classe categoria eu tenho:

@OneToMany (mappedBy="categoria") private List<SubCategoria> subcategoria;
E na classe subcategoria eu tenho:

@ManyToOne @JoinColumn(name="idCategoria") private Categoria categoria;
Nas duas classes já estou implementando a interface CycleRecoverable.
O engraçado é que estava funcionando até agora de pouco.

Eu entendo, mas você usando o GSON vai ter q escolher que lado você quer.
Para fazer isso, você tem que fazer algo deste tipo (peguei de um projeto meu).
É fácil achar na documentação do GSON como fazer isso.

Você precisa ter a “Estratégia de exclusão” e uma anotação para indicar quais campos serão excluídos.

[code]import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;

/**

  • Estratégia de exclusão de campos para o Gson usando a anotação @ExcluirJSON.

  • @author David Buzatto
    */
    public class EstrategiaExclusaoJSON implements ExclusionStrategy {

    @Override
    public boolean shouldSkipField( FieldAttributes fa ) {
    // verifica se tem a anotação da exclusão do JSON
    return fa.getAnnotation( ExcluirJSON.class ) != null;
    }

    @Override
    public boolean shouldSkipClass( Class<?> type ) {
    // aceita qualquer classe
    return false;
    }

}
[/code]

[code]import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**

  • Anotação para excluir campo do JSON gerado pelo Gson.

  • @author David Buzatto
    */
    @Retention( RetentionPolicy.RUNTIME )
    @Target( ElementType.FIELD )
    public @interface ExcluirJSON {

    // apenas marcação de campo

}[/code]
Ai, o campo que você quer remover da serialização, você anota com o @ExcluirJSON.
Exemplo:

[code]public class Foo {
@ExcluirJSON // vai remover o bar dos foos
private Bar bar;
}

public class Bar {
private List foos;
}[/code]

Por fim, para serializar, crie o GSON assim:

Gson gson = new GsonBuilder().setExclusionStrategies( new EstrategiaExclusaoJSON() ).create();

Assim, você pode criar mais de uma estratégia e criar o serializador com o que você precisa.

1 curtida

Legal cara, gostei da sua solução.
Vou fazer aqui e qualquer coisa pergunto.
Muito obrigado por compartilhar seu conhecimento.

Não sei se foi por ignorância minha, mas eu deixei de usar hibernate pra funcionar JSON rs.

Valeu David,

Estava com um problema idêntico e a sua solução funcionou perfeitamente.

Se eu fosse um cara religioso, colocaria seu nome nas minhas orações.