【问题标题】:Deserializing JSON from Hibernate从 Hibernate 反序列化 JSON
【发布时间】:2016-11-04 12:35:25
【问题描述】:

我在反序列化 Spring Boot 中的类时遇到问题。当我的控制器尝试反序列化它时,它会崩溃。这是课程:

@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]
}

这取决于这个:

@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();
    }

而垃圾传感器依赖于这个类:

@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() {
    }

}

我的控制者:

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

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

当我调用 web 服务时,我得到这个错误:

无法写入HTTP消息:org.springframework.http.converter.HttpMessageNotWritableException:无法写入内容:无法反序列化(通过引用链:java.util.ArrayList[0]-br.com.simplepass.cleanerway.domain .TrashCan["trashSensorList"]-org.hibernate.collection.internal.PersistentBag[0]-br.com.simplepass.cleanerway.domain.TrashSensor["measurementList"]);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException: 无法反序列化(通过引用链:java.util.ArrayList[0]-br.com.simplepass.cleanerway.domain.TrashCan["trashSensorList"]-org.hibernate .collection.internal.PersistentBag[0]-br.com.simplepass.cleanerway.domain.TrashSensor["measurementList"])

我无法解释这个错误=/。非常感谢您对此问题的任何帮助。

【问题讨论】:

    标签: java json spring hibernate jackson


    【解决方案1】:

    由于您的 json 正在进入循环,因此您收到此错误,为避免这种情况,请使用 @JsonIgnore 注释:

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

    【讨论】:

    • 是的......这不是唯一的地方......你必须找出更多进入循环的映射并相应地添加@JsonIgnore
    • 感谢您的快速回复!如果我这样做,我将无法使用measurementList,对吗?我需要这种依赖......所以我不能使用@JsonIgnore
    • 然后在measurementList映射上使用@JsonIgnore
    • 在你的第二个类中添加 JsonIgnore 并忽略父依赖
    • Orelse @JsonView 是一个更好的选择,您可以根据需要自定义 Json
    【解决方案2】:

    当您使用实体之间的关系时会发生这种情况。想象一下,您的 TrashCan 中有指向 Trash 的链接。你的垃圾有链接到它的包装 - 垃圾桶。因此,您尝试序列化 TrashCan 实体的同时也序列化了 Trash。然后当你序列化垃圾时,垃圾桶会在里面再次序列化。等等。这是一个循环。您可以在每个可能导致循环的实体上使用@JsonIgnore

    @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;
    

    但这是一个糟糕的方法。强烈建议您使用 DTO(数据传输对象)模式进行序列化/反序列化。它还为您提供了更大的灵活性。你可以阅读它here

    【讨论】:

    • Maksym,感谢您的阅读,这真是个好主意。我需要这些列表,所以我将 @JsonIgonre 放在 TrashCan 中,并将 TrashSensor 放在映射对象中。抱歉,但我只是看不到 DTO 将如何帮助我......这个控制器的漏洞目的是从数据库中获取数据,所以在这种情况下,直接从 POJO 中获取数据看起来真的很好。无论如何,该框架几乎可以完成所有工作。你怎么看?
    • @LeandroBorgesFerreira,DTO 被认为是最佳实践。序列化 POJO 是一个糟糕的代码。在您的情况下,如果您的应用程序不是那么大并且不会更大,您可以序列化它们。但是想一想,如果您想添加验证,或者您决定在其他地方提供不完整的实体,您将真的需要 DTO 来更改应用程序任何地方的特定情况的序列化。例如,您为所有关系留下了完整的实体,只需根据需要为任何控制器创建和序列化特殊 DTO。此外,它还使您的模型在大型应用程序中更加简洁。
    【解决方案3】:

    如果您需要 trashMeterListtrashSensorList 作为响应,请遵循此答案。

    由于休眠延迟加载和反序列化时没有会话,您会收到此异常。

    要修复,只需更改您的控制器:

        @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);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-23
      • 1970-01-01
      • 1970-01-01
      • 2011-05-16
      • 1970-01-01
      相关资源
      最近更新 更多