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

Erro ao buscar um objeto no DB.

Ola, no desenvolvimento da minha aplicação de treinamento, onde preciso buscar um orcamento, pra popular a view com seus atributos, me deparei com o erro impresso logo abaixo:

Consegui isolar o codigo e o simulei numa classeTest:

1) Classe Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/springbeans.xml")
@TransactionConfiguration
public class TestSearch {

    @Autowired
    OrcamentoGeralController ogc;

    @Test
    public void test() {

        OrcamentoGeral og = ogc.buscarPorId("3");

        List<OrcamentoGeral>  listOG = og.getCliente().getListOrcamentoGeral();

        for (OrcamentoGeral o : listOG) {
            System.out.println(o.getId());

        }
    }

2) Resultado da execução:

1
2
3

3) Ao terminar a impressao do resultado, ele exibe essa pilha de erro:

...
...
...
at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
    at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
    at com.cursoAlura5.entities.Escritorio.hashCode(Escritorio.java:19)
    at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
2017-04-29 10:37:28,801 ERROR org.springframework.beans.factory.support.DefaultListableBeanFactory - Destroy method on bean with name 'perfilController' threw an exception
java.lang.StackOverflowError
    at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
    at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
    at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
    at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
    at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
....
....
....
    at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
    at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
    at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
2017-04-29 10:37:28,806 INFO  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'fabricaConexao'
2017-04-29 10:37:28,806 INFO  org.hibernate.impl.SessionFactoryImpl - closing

4) Classe Cliente:

@Entity @ManagedBean @Data
public class Cliente implements Serializable {

    @OneToMany
    private List<OrcamentoGeral>     listOrcamentoGeral ;

5) Classe OrcamentoGeral:

@Entity @ManagedBean @Data
public class OrcamentoGeral implements Serializable {

    @ManyToOne(cascade = CascadeType.ALL)
    private                                               Cliente  cliente;

Alguem pode me dar uma ideia fazendo o favor do que estar acontecendo?

14 respostas

E aí, Jonas! Tudo certo, cara? =)

Aparentemente, há um erro com sua classe Escritorio, você poderia postá-la aqui, por favor? =)

Ahh, além disso, coloca a Stack Trace completa também! Assim podemos auxiliá-lo de forma mais precisa...

Fábio

Bom dia Fabio, segue a Classe Escritorio:

@Entity @ManagedBean @Data
public class Escritorio implements Serializable {

    private static final long serialVersionUID = 1L;
    @Version
    private Long version;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer           id;

    @OneToOne(cascade = CascadeType.ALL)
    private Perfil            proprietario;
    private String            nomeComercial;
    @OneToMany
    private List<Colaborador> listColaboradores;
    @OneToMany
    private List<Cliente>     listClientes;
    @OneToMany
    private List<Fornecedor>  listFornecedor;
    @OneToMany
    private List<Perfil>      listParceiros;
    @OneToMany 
    private List<Servico>     listServicos;

    private String Rua;
    private String numero;
    private String Bairro;
    private String Cidade;
    private String Estado;
    private String pais;
    private String foneFixo;
    private String whats;
    private String skype;
    private String twitter;
    private String Email;
    private String site;


}
linha 19: public class Escritorio implements Serializable {
@Entity @ManagedBean @Data
public class Perfil implements Serializable {

    private static final long serialVersionUID = 1L;
    @Version
    private Long       version;//

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer    Id;
    @Lob 
    private byte[]     imagemPerfil;
    @Lob 
    private byte[]     imagemPerfilBanner;
    private String     perfilName;
    private String     sexo;
    private String     genero;
    private String     rg;/*    @Column(unique=true)*/
    private String     cpf;
    private String     perfilEmail;
    private String     whats;
    private String     foneComercial;
    private String     cep;
    private String     rua;
    private String     cidade;
    private String     estado;
    private String     numero;
    private String     renda;
    private String     password;
       private String     idade;
    private String     instituicaoFormacao;
    private String     curso="Arquiteto";
    private String     anoFormatura;
    private String     turma;
    private String     matricula;
    private String     obs;
    private String     CAU;
    private String     formacao;
    private Boolean    active=true;
    private Boolean    concordoTermoPrivacidade=false;
    @OneToOne
    private Escritorio escritorio;

}
LInha17: public class Perfil implements Serializable {
at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
at com.cursoAlura.entities.Escritorio.hashCode(Escritorio.java:19)
at com.cursoAlura.entities.Perfil.hashCode(Perfil.java:17)
2017-04-29 10:37:28,806 INFO  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'fabricaConexao'
2017-04-29 10:37:28,806 INFO  org.hibernate.impl.SessionFactoryImpl - closing

Quebrando a cabeca pra descobrir o erro, suspeito que seja por que:

Escritorio tem listCliente onde cada cliente tem Escritorio, que tem listCliente. e assim infinitamente.

Será que seria isso mesmo, se for, como sair dele?

Jonas uma coisa estranha que eu vi no seu código é.

@Entity @ManagedBean @Data
public class Escritorio implements Serializable {

Essas anotação data e managedBean, não entendo o porque delas ai, deixa só como @Entity para ver.

Jonas,

Acredito que não seja esse o motivo, não. Rs. A menos que o mapeamento esteja incorreto.

Mas agora que vi, há uma menção sobre um PerfilController, pode colocá-lo aqui? =)

Fábio

Obrigado Fabio e Alisson pelas respostas.

Descobri o problema, não era o Escritorio e o Cliente que estava gerando o loop infinito, era o Escritorio e o Perfil.

Comentei o relacionamento @OneToOne do atributo escritorio, na Classe Perfil, e resolveu.

@Entity @ManagedBean @Data
public class Perfil implements Serializable {
//    @OneToOne
    private Escritorio escritorio;

Respondendo ao questionamento do Alisson: 1) Anotação @Data, ela insere automaticamente os getter e setter pra nao precisar ficar dando CTRL+F3, cada vez que altera os atributos do bean. Não é boa pratica usar getters e setter abusiavamente, mas como é uma aplicacao web e preciso dar getter e setter em praticamente todos os atributos, entao uso ele. 2) Anotacao @ManagedBean, estou usando o JSF, essa anotação incluir o bean no contexto do JSF.

Jonas,

Tem certeza que está resolvido? Rs. Pergunto, porque acredito que a JPA precisará reconhecer esse mapeamento de alguma forma.

Como você colocou o @OneToMany no atributo da classe Escritório, acho que seria interessante colocar um @ManyToOne do outro lado. E ainda colocar o mappedBy no lado do Escritorio...

Fábio

Fabio, resolveu, mas criou problema em outro lugar, Vou fazer a sugestão que você falou, pra ver o que dá.

Jonas,

E aí, resolveu? =)

Fábio

Bom dia Fabio, parei ontem, retomei agora a poco... postarei assim que tiver uma conclusão do que você sugeriu.

OI Fábio, não sei se entendi direito o que você quis dizer, porque a classe Escritério tem mais de um atributo do tipo Perfil com seus respectivos relacionamentos, mas o que esta dando problema é esse relacionamento.

1) Clase Escritorio:

@Entity @ManagedBean @Data
public class Escritorio implements Serializable {

    @OneToOne(cascade = CascadeType.ALL)
    private Perfil            proprietario;

2) Classe Perfil:

@Entity @ManagedBean @Data
public class Perfil implements Serializable {

    @OneToOne
    private Escritorio escritorio;

}

Quando eu comento o relacionamento abaixo, resolve, nao da mais a StackTrace que postei:

//@OneToOne(mappedBy="proprietario")
    private Escritorio escritorio;

Só que ai eu crio um problema em outro lugar.

@Controller @ViewScoped
public class EscritorioController {

escritorio.setProprietario(perfilController.getPerfil());
perfilController.getPerfil().setEscritorio(escritorio);
        }
    }
    public void salvar(){
        escritorioService.salvar(escritorio);

Quando eu salvo a Entity escritorio, o CASCADE, salva o a Entity perfil automaticamente. Mas, ao remover o relacionamento bidirecional, nao salva mais a Entity peril, entao teria que salvar "manualmente" , sem o recurso do CASCADE. Nao sei se essa seria a forma corretar de resolver o problema, como estou aprendendo gostaria de aprender fazer do jeito certo.

Jonas,

Vixi... Não tinha me atentado a uma coisa... A classe Escritorio possui dois atributos que envolvem a classe Perfil...

@Data
@Entity
@ManagedBean
public class Escritorio {
    @OneToOne
    private Perfil proprietario;

    @OneToMany
    private List<Perfil> listParceiros;

    // Restante do código...
}

Não sei se a JPA consegue resolver esse código, porque a classe Perfil deveria ter dois mapeamentos: uma para o @OneToOne (proprietario) e um @ManyToOne, para o @OneToMany (listParceiros), sacou? =|

Uma possível solução é colocar o proprietário dentro da lista de parceiros e, colocar um atributo na classe Perfil, para indicar que ele é o proprietário... O que acha?

Tirando isso, eu não sei como contornar o seu problema... Vou continuar pesquisando e, se achar alguma coisa, eu posto aqui para lhe ajudar, pode ser? =)

Fábio

Obrigado Fabio, vou tentar resolver considerando suas sugestoes,,,

solução!

Problema solucionado: a @Data do projeto Lombok que estava causando o erro.

import lombok.Data;

@Entity @ManagedBean @Data
public class Cliente implements Serializable

Essa anotação insere automaticamente os metodos GETTERS, os SETTERS, o toString() e o HashCode().

Ao remove-la, o código executou sem erro.

Não sei exatamente o porque ocorreu o erro, mas nos haschCode que inseri manualmente na Classe Escritório e na Classe Perfil, setei só o Id.

Nao verifiquei a fundo pra descobrir o motivo, mas presumo que os HashCode gerado pela @Data estava pegando todos os atributos dos beans, gerando um codigo hasch muito complexo. Ou talvez um atributo, como version, ou o serialVersionUID , que o Data incluíra no hascCode possa ter gerado o erro.

Obrigado ao Fabio e ao Alisson que responderam. O erro foi ótimo pra consolidar conhecimento sobre relacionamento, e suas sugestões ajudaram muito.

Vou encerrar o tópico.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software