Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON parse error: Already had POJO for id

I already saw some question about this topic but i could not apply it to my case because I tried to apply them and the error continued. so I come to expose my situation.

I read some comments about it and said that if I changed the name of my column idEntidade in the class Entidade i could succeed. But I can not change the database.

I trying to put scope= Distritos.class in my @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "idDistrito") but it did not work.

I need help.

I am trying to persist the data in my database using spring MVC with Angular. When I click save the data i got this error

2017-09-29 13:28:02.126  WARN 2716 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Already had POJO for id (java.lang.Long) [[ObjectId: key=1, type=com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator, scope=java.lang.Object]]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Already had POJO for id (java.lang.Long) [[ObjectId: key=1, type=com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator, scope=java.lang.Object]] (through reference chain: digifred.global.model.Distritos["idEntidade"]->digifred.global.model.Entidades["idEntidade"])
2017-09-29 13:28:02.126  WARN 2716 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Already had POJO for id (java.lang.Long) [[ObjectId: key=1, type=com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator, scope=java.lang.Object]]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Already had POJO for id (java.lang.Long) [[ObjectId: key=1, type=com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator, scope=java.lang.Object]] (through reference chain: digifred.global.model.Distritos["idEntidade"]->digifred.global.model.Entidades["idEntidade"])
2017-09-29 13:46:14.096  INFO 2716 --- [      Thread-46] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@53b2ae5: startup date [Fri Sep 29 13:23:36 BRT 2017]; root of context hierarchy

I have these class

@Entity
@Table(name = "distritos", schema="glb")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Distritos.findAll", query = "SELECT d FROM Distritos d"),
    @NamedQuery(name = "Distritos.findByIdDistrito", query = "SELECT d FROM Distritos d WHERE d.idDistrito = :idDistrito"),
    @NamedQuery(name = "Distritos.findByNome", query = "SELECT d FROM Distritos d WHERE d.nome = :nome"),
    @NamedQuery(name = "Distritos.findByCodigoDne", query = "SELECT d FROM Distritos d WHERE d.codigoDne = :codigoDne"),
    @NamedQuery(name = "Distritos.findByFlagAtivo", query = "SELECT d FROM Distritos d WHERE d.flagAtivo = :flagAtivo")})




@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "idDistrito")        
public class Distritos implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id_distrito")
    private Long idDistrito;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 70)
    @Column(name = "nome")
    private String nome;
    @Size(max = 8)
    @Column(name = "codigo_dne")
    private String codigoDne;
    @Column(name = "flag_ativo")
    private Integer flagAtivo;
    @JoinColumn()
    @ManyToOne
    private Entidades idEntidade;
    @JoinColumn()
    @ManyToOne(optional = false)
    private Municipios idMunicipio;
    @JoinColumn()
    @ManyToOne(optional = false)
    private Ufs idUf;

  gets and sets .. 
}

Class Entidades

@Entity
@Table(name = "entidades", schema="glb")
@XmlRootElement
@NamedQueries({
    @NamedQuery(name = "Entidades.findAll", query = "SELECT e FROM Entidades e"),
    @NamedQuery(name = "Entidades.findByIdEntidade", query = "SELECT e FROM Entidades e WHERE e.idEntidade = :idEntidade"),
    @NamedQuery(name = "Entidades.findByBairro", query = "SELECT e FROM Entidades e WHERE e.bairro = :bairro"),
    @NamedQuery(name = "Entidades.findByBrasao", query = "SELECT e FROM Entidades e WHERE e.brasao = :brasao"),
    @NamedQuery(name = "Entidades.findByCnpj", query = "SELECT e FROM Entidades e WHERE e.cnpj = :cnpj"),
    @NamedQuery(name = "Entidades.findByComplemento", query = "SELECT e FROM Entidades e WHERE e.complemento = :complemento"),
    @NamedQuery(name = "Entidades.findByEmail", query = "SELECT e FROM Entidades e WHERE e.email = :email"),
    @NamedQuery(name = "Entidades.findByLogradouro", query = "SELECT e FROM Entidades e WHERE e.logradouro = :logradouro"),
    @NamedQuery(name = "Entidades.findByNome", query = "SELECT e FROM Entidades e WHERE e.nome = :nome"),
    @NamedQuery(name = "Entidades.findByNumero", query = "SELECT e FROM Entidades e WHERE e.numero = :numero"),
    @NamedQuery(name = "Entidades.findBySigla", query = "SELECT e FROM Entidades e WHERE e.sigla = :sigla"),
    @NamedQuery(name = "Entidades.findByTelefone", query = "SELECT e FROM Entidades e WHERE e.telefone = :telefone")})


@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "idEntidade")  
public class Entidades implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    private Long idEntidade;
    @Size(max = 50)
    private String bairro;
    private BigInteger brasao;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 14)
    private String cnpj;
    @Size(max = 20)
    private String complemento;
    // @Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="E-mail inválido")//if the field contains email address consider using this annotation to enforce field validation
    @Size(max = 30)
    private String email;
    @Size(max = 50)
    private String logradouro;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 70)
    private String nome;
    @Size(max = 20)
    private String numero;
    @Basic(optional = false)
    @NotNull
    @Size(min = 1, max = 4)
    private String sigla;
    @Size(max = 12)
    private String telefone;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<EntidadesAdministradores> entidadesAdministradoresCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "entidades")
    private Collection<Bairros> bairrosCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<PessoasDeficiencias> pessoasDeficienciasCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<PessoasEnderecos> pessoasEnderecosCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<EntidadesLicencas> entidadesLicencasCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<PessoasContatos> pessoasContatosCollection;
    @OneToMany(mappedBy = "idEntidade")
    private Collection<Logradouros> logradourosCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<Pessoas> pessoasCollection;
    @JoinColumn()
    @ManyToOne(optional = false)
    private Municipios idMunicipio;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "idEntidade")
    private Collection<PessoasCaracteristicas> pessoasCaracteristicasCollection;

    public Entidades() {
    }
          .... gets and sets . . 

    }

Class DistritosController

@RestController
@RequestMapping(value="/user")
public class DistritosController {

    @Autowired
    DistritosService distritosService; 


    @RequestMapping(method = RequestMethod.POST, value = "/distritos", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Distritos> cadastrarDistritos(@RequestBody Distritos distritos) {
        Distritos distritosCadastrado = distritosService.cadastrar(distritos);
        return new ResponseEntity<Distritos>(distritosCadastrado, HttpStatus.CREATED);
    }

    @RequestMapping(method = RequestMethod.GET, value = "/distritos", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Collection<Distritos>> buscarTodosDistritos() {
        Collection<Distritos> distritosBuscados = distritosService.buscarTodos();
        return new ResponseEntity<>(distritosBuscados, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.GET, value = "/distritos/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Distritos> buscarDistritosPorId(@PathVariable int id) {
        Distritos distritos = distritosService.buscaPorId(id);
        return new ResponseEntity<>(distritos, HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.DELETE, value = "/distritos/{id}")
    public ResponseEntity<Distritos> excluirDistritos(@PathVariable int id) {
        Distritos distritoEncontrado = distritosService.buscaPorId(id);
        if (distritoEncontrado == null) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        distritosService.excluir(distritoEncontrado);
        return new ResponseEntity<>(HttpStatus.OK);
    }

    @RequestMapping(method = RequestMethod.PUT, value = "/distritos", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Distritos> alterarDistritos(@RequestBody Distritos distritos) {
        Distritos distritoAlterado = distritosService.alterar(distritos);
        return new ResponseEntity<Distritos>(distritoAlterado, HttpStatus.OK);
    }


}

enter image description here

enter image description here

enter image description here

like image 937
Eduardo Krakhecke Avatar asked Sep 29 '17 17:09

Eduardo Krakhecke


1 Answers

There are two issues:

1. Identity scopes

Both of @JsonIdentityInfo's should be scoped, since both of your classes have the same generator type - ObjectIdGenerators.PropertyGenerator.class.

Scope is used to define applicability of an Object Id: all ids must be unique within their scope; where scope is defined as combination of this value and generator type. Comparison is simple equivalence, meaning that both type generator type and scope class must be the same. Scope is used for determining how many generators are needed; more than one scope is typically only needed if external Object Ids have overlapping value domains (i.e. are only unique within some limited scope)

For Distritos:

@JsonIdentityInfo(scope = Distritos.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "idDistrito")

And for Entidades:

@JsonIdentityInfo(scope = Entidades.class, generator = ObjectIdGenerators.PropertyGenerator.class, property = "idEntidade")

2. Field naming

@JoinColumn()
@ManyToOne
private Entidades idEntidade;

somehow interferes with

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
private Long idEntidade;

when you're passing to the Jackson deserializer a full Distritos object (containing Entidades inside, as in your example).

I've done some debugging and found that BeanDeserializer (which resolves fields by name) failed to deserialize property field, as it named same as id field, so I've changed idEntidade to entidade in Distritos class.

After these changes my sample project works fine (as I've deleted some fields from your classes - Distritos.idMunicipio, Distritos.idUf and all the Collections from Entidades). You have to check, if other classes (e.g. Municipios and Ufs) have the same issues, and fix them too.

like image 132
Anatoly Shamov Avatar answered Sep 23 '22 03:09

Anatoly Shamov