反序列化ManyToOne关系时Jackson- Lazy List初始化错误

iih3973s  于 2023-05-06  发布在  其他
关注(0)|答案(3)|浏览(161)

我有两个简单的类:

  • Cat
  • CatStore

Cat没有什么特别的,而CatStore有一个List<Cat>,关系Map为:
Cat类中:

@ManyToOne
private CatStore catstore;

CatStore中:

@OneToMany(mappedBy="catstore", fetch=FetchType.EAGER)
private List<Cat> cats;

这个关系看起来工作正常,因为当我运行时,Jackson可以生成正确的JSON

String json = mapper.writeValueAsString(catStore);

但是如果我尝试反序列化我刚刚生成的JSON,使用这行:

CatStore c2 = mapper.readValue(json, CatStore.class);

我得到一个JsonProcessingException

failed to lazily initialize a collection, could not initialize proxy - no Session (through reference chain: fr.truc.java.cleanspringbootMVC.model.CatStore["cats"]

如果CatStore中没有cats,反序列化实际上可以工作,如下面的JSON:

{
  "id":123,
  "cats":["org.hibernate.collection.internal.PersistentBag",[]],
  "name":"NO cats"
}

但这一个触发了错误:

{
    "id": 121,
    "cats": ["org.hibernate.collection.internal.PersistentBag", [
        ["fr.truc.java.cleanspringbootMVC.model.Cat", {
            "id": 118,
            "name": "luc",
            "nbPattes": 4
        }],
        ["fr.truc.java.cleanspringbootMVC.model.Cat", {
            "id": 119,
            "name": "andré",
            "nbPattes": 4
        }],
        ["fr.truc.java.cleanspringbootMVC.model.Cat", {
            "id": 120,
            "name": "cheval",
            "nbPattes": 4
        }]
    ]],
    "name": "Cat en kit"
}

我真的不知道为什么延迟加载异常会在这里触发,因为数据包含在JSON字符串中。
这与PersistentBag有关吗?
这是因为我没有使用自定义序列化器/反序列化器吗?

v7pvogib

v7pvogib1#

如果使用JPA,所有实体都将通过字节码增强,以允许延迟加载等。它们实际上并不适合序列化,除了hibernate,hibernate意识到了这一点。但是Jackson并不知道这件事,所以它会破坏增强的字节码。
对于JPAMap和JacksonMap使用同一个类也不是一个好主意。JPA类具有Map到列等的字段,而Jackson的类Map到javascript模式。如果你在同一个类中使用它们,你永远无法在不影响JSON模式的情况下更改数据库模式,并且可能会破坏与使用JSON的人的向后兼容性。
最好有单独的类(DTO)用于Jackson,并在它们之间进行一些Map。或者使用mapstruct自动生成Map器。

flmtquvp

flmtquvp2#

错误似乎与mapper.enableDefaultTyping();有关
启用后,每个类的类型都以JSON输出。(我想要的)
由于某种原因,它会在@ManyToOne上导致上述错误
当禁用时,PersistentBag不再出现在我的序列化JSON中,并且反序列化工作...

s3fp2yjn

s3fp2yjn3#

我也遇到了同样的问题。要在使用enableDefaultTyping(或当前推荐的activateDefaultTyping)时修复它,我必须使用Hibernate5Module:(注意,所需的模块取决于您的hibernate版本,必须作为附加依赖项添加。)

mapper.registerModule(new Hibernate5Module()
   .configure(Hibernate5Module.Feature.REPLACE_PERSISTENT_COLLECTIONS, true));

这会将输出中的PersistentBag替换为ArrayList,并防止反序列化错误。
然而,这个功能似乎不适用于FetchType.EAGER,原因我不知道。幸运的是,@Fetch(FetchMode.JOIN)做到了这一点。
另一件需要考虑的事情是,REPLACE_PERSISTENT_COLLECTIONS特性为我生成了格式错误的JSON(将列表内容 Package 在双方括号中)。但这是通过使用宽松的反序列化解决的。

相关问题