1
resposta

Relacionamentos

Boa noite pessoas...

Estou tentando fazer o seguinte:

Tenho duas tabelas no meu banco de dados uma para Usuário e outra para Senha. Quem fez o banco de dados criou um relacionamento bi-direcional OneToOne.

Então fiz as seguintes classes de modelo:

Classe Usuario

@Entity
public class Usuario implements Serializable {
    @Id
    @SequenceGenerator(name = "SQ_ID_USUARIO", sequenceName = "SQ_ID_USUARIO", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_ID_USUARIO")
    @Column(name = "ID", nullable = false, length = 10)
    private Long id

    private String nome;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_SENHA", nullable = true)
    private Senha senha;

    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id
    }

    public String getNome() {
        return this.nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public Senha getSenha() {
        return this.senha;
    }

    public void setSenha(Senha senha) {
        this.senha = senha;
    }
}

Classe Senha

@Entity
public class Senha implements Serializable {

    @Id
    @SequenceGenerator(name = "SQ_ID_SENHA", sequenceName = "SQ_ID_SENHA", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_ID_SENHA")
    @Column(name = "ID", nullable = false, length = 10)
    private Long id;

    private String valor;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_USUARIO", nullable = true)
    private Usuario usuario;

    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }

    public String getValor() {
        return this.valor;
    }
    public void setValor(String valor) {
        this.valor = valor;
    }

    public Usuario getUsuario() {
        return this.usuario;
    }
    public void setValor(Usuario ususario) {
        this.usuario = usuario;
    }
}

O problema é que quando tento fazer um select Por exemplo

     ...
    @Autowired
    UsuarioDao usuarioDao;

    public Usuario getUsuarioById(Long id) {
        Usuario u = usuarioDao.findOne(id);
        return u;
    }

classe UsuarioDao

@Repository
public interface UsuarioDao extends JpaRepository<Usuario, Long> {

}

Mas ao tentar executar recebo uma exceção que não consigo ver por que o console fica cheio assim:

    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:689) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:689) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:689) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155) ~[jackson-databind-2.8.10.jar:2.8.10]
    at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:704) ~[jackson-databind-2.8.10.jar:2.8.10]
    at

O que estou fazendo de errado ?

1 resposta

Oi Jorge,

Bom, achei estranho esse esquema da senha estar em uma outra tabela separada... Normalmente a senha fica na propria tabela de usuarios, como uma coluna.

Se o motivo for para garantir que a senha seja única, dá para fazer assim:

public class Usuario {
    @Column(unique = true)
    private String senha;
}

Mas enfim, se não der para fazer essa mudança, o problema ocorre porque como o relacionamento é bidirecional, um dos lados do @ManyToOne precisa estar como mappedBy. No caso poderia seria na sua classe Senha:

    @OneToOne(fetch = FetchType.LAZY, mappedBy="senha")
    @JoinColumn(name = "ID_USUARIO", nullable = true)
    private Usuario usuario;

Isso é algo da JPA em si, mas seu erro está ocorrendo na serialização para JSON feita pela biblioteca Jackson, que entra em loop infinito por conta do relacionamento ser bidirecional.

Para evitar o erro, adicione as anotações do jackson nas classes Usuario e Senha:

public class Usuario {
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ID_SENHA", nullable = true)
    @JsonManagedReference
    private Senha senha;
}
public class Senha {
    @OneToOne(fetch = FetchType.LAZY, mappedBy="senha")
    @JoinColumn(name = "ID_USUARIO", nullable = true)
    @JsonBackReference
    private Usuario usuario;
}

Veja se resolve.

Bons estudos!

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