简体   繁体   中英

Deserializing JSON from Hibernate

I'm having a problem de deserializing a class in Spring Boot. When my controller tries to deserialize it, it crashes. Here is the class:

@Entity
@Table(name="trash_cans")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
public class TrashCan {
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="TRASH_CAN_ID")
    long id;

    @Column(name="TRASH_CAN_NAME")
    String name;

    @ManyToOne
    @JoinColumn(name="PLACE_ID")
    private Place place;

    @OneToMany(mappedBy="trashCan", targetEntity=TrashMeter.class, fetch=FetchType.LAZY)
    private List<TrashCan> trashMeterList;

    @OneToMany(mappedBy="trashCan", targetEntity=TrashSensor.class, fetch=FetchType.LAZY)
    private List<TrashSensor> trashSensorList;

    public TrashCan() {     
    }

    public TrashCan(long id, String name) {
        super();
        this.id = id;
        this.name = name;
    }

    [getters and setters]
}

That depends on this one:

@Entity
@Table(name="trash_sensor")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
public class TrashSensor {

    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    @Column(name="name")
    private String name;

    @Column(name="description")
    private String description;

    @ManyToOne
    @JoinColumn(name="TRASH_CAN_ID")
    private TrashCan trashCan;

    @OneToMany(mappedBy = "trashSensor", targetEntity = Measurement.class, fetch = FetchType.LAZY)
    private List<Measurement> measurementList;

    public TrashSensor() {
        super();
    }

And Trash Sensor Depends on this Class:

@Entity
@Table(name="measurement")
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property="id")
public class Measurement {

    @Id
    @Column(name="id")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;

    @Column(name="value")
    private float value;

    @Column(name="last_measure")
    private LocalDateTime dateTime;

    @ManyToOne
    @JoinColumn(name="trash_sensor_id")
    private TrashCan trashSensor;

    public Measurement() {
    }

}

My Controler:

@RequestMapping(value="/trashCan", method=RequestMethod.GET)
    public ResponseEntity<Iterable<TrashCan>> getPlaces(){
        Iterable<TrashCan> trashCanIterable = trashCansRepository.findAll();

        return new ResponseEntity<>(trashCanIterable, HttpStatus.OK);
    }

When I call the webservice, I get this error:

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: could not deserialize (through reference chain: java.util.ArrayList[0]-br.com.simplepass.cleanerway.domain.TrashCan["trashSensorList"]-org.hibernate.collection.internal.PersistentBag[0]-br.com.simplepass.cleanerway.domain.TrashSensor["measurementList"]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: could not deserialize (through reference chain: java.util.ArrayList[0]-br.com.simplepass.cleanerway.domain.TrashCan["trashSensorList"]-org.hibernate.collection.internal.PersistentBag[0]-br.com.simplepass.cleanerway.domain.TrashSensor["measurementList"])

I can't interpret this error =/ . Any help with this problem greatly appreciated.

You are getting this error since your json is entering a loop, to avoid this, use @JsonIgnore annotation:

@OneToMany(mappedBy = "trashSensor", targetEntity = Measurement.class, fetch = FetchType.LAZY)
@JsonIgnore
private List<Measurement> measurementList;

It happens when you use relations between entities. Imagine that your TrashCan has link to Trash in it. And your trash has link to it's wrapper - trashcan. So what you try to serialize TrashCan entity you also serializing Trash. And then when you are serializing trash trashcan is serialized again inside it. And so on. It's a loop. You can use @JsonIgnore on every entity that may cause loop.

@JsonIgnore
@ManyToOne
@JoinColumn(name="PLACE_ID")
private Place place;

@JsonIgnore
@OneToMany(mappedBy="trashCan", targetEntity=TrashMeter.class, fetch=FetchType.LAZY)
private List<TrashCan> trashMeterList;

@JsonIgnore
@OneToMany(mappedBy="trashCan", targetEntity=TrashSensor.class, fetch=FetchType.LAZY)
private List<TrashSensor> trashSensorList;

But it's a bad way. It's strongly recommended to use DTO (Data transfer object) pattern for you serialization/deserialization. It also gives you more flexibility. You can read about it here

If you need trashMeterList and trashSensorList in response then follow this answer.

Due to hibernate lazy loading and no session while deserialisation, you are getting this exception.

To fix just change your controller:

    @RequestMapping(value="/trashCan", method=RequestMethod.GET)
    public ResponseEntity<Iterable<TrashCan>> getPlaces(){
        Iterable<TrashCan> trashCanIterable = trashCansRepository.findAll();
        List<TrashCan> responseList = new ArrayList<TrashCan>(trashCanIterable.size())
        while(trashCanIterable.hasNext()){
            TrashCan trashCan = trashCanIterable.next();
            for(TrashMeter trashMeter : trashCan.trashMeterList){

            }
            for(TrashSensor trashSensor : trashCan.trashSensorList){

            }
            responseList.add(trashCan);
        }
        return new ResponseEntity<>(responseList, HttpStatus.OK);
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM