【问题标题】:Gson and Jackson both fails to initialize a lazy collectionGson 和 Jackson 都无法初始化惰性集合
【发布时间】:2017-08-13 09:31:38
【问题描述】:

到目前为止,我对 Gson/Jackson 还没有深入的了解。请多多包涵。我必须将我的对象转换为 json 字符串。我已经尝试过 GsonJackson。我的对象有一个集合,默认情况下具有 Fetch,它是延迟加载。当我使用 session.get 获取对象并使用 Gson 的 gson.toJson(object); 进行转换时,它无法初始化该惰性集合。

1。我不想急于求成。

2。我也不想忽视它。

我只想要它应该返回 null 或为空的任何方式,而不是搞乱延迟加载收集。因为据我所知,如果它依赖于休眠,那么就不可能将它从会话中取出。是否有任何解决方法(在 Gson 或 Jackson 中)这个问题我不想总是初始化集合(但有时是肯定的)

@Entity
@JsonInclude(Include.NON_NULL)
public class Category {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;
    @ManyToMany
    private List<Item> itemList;
    //getter setter
}

在main方法中

Session s = sessionFactory.openSession();
Transaction t = s.getTransaction();
t.begin();
Category category = null;
try{
    category = s.get(Category.class, 1);
    t.commit();
}catch(Exception e){
    e.printStackTrace();
}finally{
    s.close();
}

try {
    Gson json = new Gson();
    String categoryString = json.toJson(category);
    System.out.println(categoryString);
} catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

它抛出

org.hibernate.LazyInitializationException:无法延迟初始化角色集合:com.company.entity.Category.itemList,无法初始化代理 - 无会话

【问题讨论】:

  • 您能否调试您的代码并检查您要序列化的对象是否真的是瞬态的并且不再是代理? GSON 被实现为忽略空值,因此它应该忽略一个为空的集合。但是,如果您有一个代理对象,则该集合就在那里,但是当您尝试在会话之外使用它时,它会失败并出现异常。
  • @thst 从休眠会话中获取后如何显式地使对象瞬态或代理?你能解释一下吗? cox 我正在使用@JsonInclude(Include.NON_NULL) 但错误仍然存​​在。

标签: java json hibernate jackson gson


【解决方案1】:

我会发布一个答案,因为它不是这里引用的问题的欺骗。还有另一个针对杰克逊的问题,但该答案仅涵盖杰克逊。 Hibernate and Jackson lazy serialization

在使用Gson 持久化对象之前,您需要确保您的集合不再充满代理,并且惰性集合确实是null,而不是如果不在会话中将失败的代理(这是您收到的LazyInitializationException

如本问题所述,您可以要求 hibernate 使用此代码为您提供实现对象而不是代理(引用自 Converting Hibernate proxy to real object):

public static <T> T initializeAndUnproxy(T entity) {
    if (entity == null) {
        throw new 
           NullPointerException("Entity passed for initialization is null");
    }

//    Hibernate.initialize(entity);
    if (entity instanceof HibernateProxy) {
        entity = (T) ((HibernateProxy) entity).getHibernateLazyInitializer()
                .getImplementation();
    }
    return entity;
}

在你的情况下,我想你不希望发生initialize() 调用,所以我注释掉了那行。

您的代码现在应该是:

   Session s = sessionFactory.openSession();
    Transaction t = s.getTransaction();
    t.begin();
    Category category = null;
    try {
        category = s.get(Category.class, 1);
        t.commit();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        s.close();
    }

    try {
        // No more hibernate messing with my object...
        Category theRealThing = initializeAndUnproxy(category);

        Gson json = new Gson();
        String categoryString = json.toJson(theRealThing);
        System.out.println(categoryString);
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

更新:至于评论,您的班级不再是代理。另一个建议是使用自定义 Gson 序列化程序。

我不会给出完整的例子,但你可以在这里找到讨论:https://groups.google.com/forum/?nomobile=true#!topic/google-gson/kDZjEXap_PE

基本上,您为集合或列表类型注册一个 Gson 类型适配器。然后在集合对象上使用Hibernate.isInitialized()。如果是,则将其序列化,如果不是,则返回null。

【讨论】:

  • 感谢您的回复。实际上 Category 本身不是代理,它只包含作为 PersistentBag 的 itemList,我不想加载它,这意味着我不想让 hibernate 查询数据库以获取它的条目。它应该只返回 null 或空。在上面的代码中,当我将 Category 对象传递给此函数时,条件 entity instanceof HibernateProxy 失败。
猜你喜欢
  • 2012-09-14
  • 2018-12-12
  • 1970-01-01
  • 2014-05-03
  • 2021-06-15
  • 2016-11-10
  • 2020-11-25
  • 2019-01-24
  • 1970-01-01
相关资源
最近更新 更多