无法编写JSON:无法延迟初始化角色集合 [英] Could not write JSON: failed to lazily initialize a collection of role

查看:146
本文介绍了无法编写JSON:无法延迟初始化角色集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试使用java-hibernate-spring实现服务器REST,该服务器将返回json.

I try to implement a server REST with java - hibernate - spring, which returns a json.

我已经映射了多对多关系.

I have map a many to many relation.

我会更好地解释,我有一个供应商,其中列出了成分列表,每种成分都有一个供应商列表.

I explain better, I have a supplier that have a list of ingredients, and each ingredient has a list of supplier.

我创建了表格:

CREATE TABLE supplier_ingredient (
  supplier_id BIGINT,
  ingredient_id BIGINT
)


ALTER TABLE supplier_ingredient ADD CONSTRAINT supplier_ingredient_pkey 
PRIMARY KEY(supplier_id, ingredient_id);

ALTER TABLE supplier_ingredient ADD CONSTRAINT 
fk_supplier_ingredient_ingredient_id FOREIGN KEY (ingredient_id) 
REFERENCES ingredient(id);

ALTER TABLE supplier_ingredient ADD CONSTRAINT 
fk_supplier_ingredient_supplier_id FOREIGN KEY (supplier_id) REFERENCES 
supplier(id);

然后我有成分模型:

.....
.....
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
....
....

然后我有供应商模型:

....
@ManyToMany
@JoinTable( name = "supplier_ingredient ", 
        joinColumns = @JoinColumn(name = "supplier_id", referencedColumnName = "id"), 
        inverseJoinColumns = @JoinColumn(name = "ingredient_id", referencedColumnName = "id"), 
        foreignKey = @ForeignKey(name = "fk_supplier_ingredient_supplier_id"))
@OrderBy("created DESC")
@Cascade(CascadeType.SAVE_UPDATE)
@BatchSize(size = 1000)
private List<Ingredient> ingredients = new ArrayList<>();
....

端点:

@RequestMapping(value = "/{supplierId:[0-9]+}", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public SupplierObject get(@PathVariable Long supplierId) {

    Supplier supplier = supplierService.get(supplierId);

    SupplierObject supplierObject = new SupplierObject (supplier);

    return SupplierObject;

}

服务

....
public Supplier get(Long supplierId) {

    Supplier supplier = supplierDao.getById(supplierId); (it does entityManager.find(entityClass, id))

    if (supplier == null) throw new ResourceNotFound("supplier", supplierId);

    return supplier;
}
....

SupplierObject

    @JsonIgnoreProperties(ignoreUnknown = true)
    public class SupplierObject extends IdAbstractObject {

    public String email;

    public String phoneNumber;

    public String address;

    public String responsible;

    public String companyName;

    public String vat;

    public List<Ingredient> ingredients = new ArrayList<>();

    public SupplierObject () {

    }

    public SupplierObject (Supplier supplier) {

        id = supplier.getId();
        email = supplier.getEmail();
        responsible = supplier.getResponsible();
        companyName = supplier.getCompanyName();
        phoneNumber = supplier.getPhone_number();
        ingredients = supplier.getIngredients();
        vat = supplier.getVat();
        address = supplier.getAddress();


    }
}

IdAbstractObject

public abstract class IdAbstractObject{

    public Long id;

}

我的问题是,当我呼叫端点时:

My problem is, when I call the endpoint:

http://localhost:8080/supplier/1

我遇到一个错误:

无法编写JSON:无法延迟初始化的集合 角色:myPackage.ingredient.Ingredient.suppliers,无法初始化 代理-没有会话;嵌套的例外是 com.fasterxml.jackson.databind.JsonMappingException:懒惰地失败 初始化角色集合: myPackage.ingredient.Ingredient.suppliers,无法初始化代理 -无会话(通过参考链:myPackage.supplier.SupplierObject [\"ingredients \"]-> org.hibernate.collection.internal.PersistentBag [0]-> myPackage.ingredient.Ingredient [\"suppliers \"])"

"Could not write JSON: failed to lazily initialize a collection of role: myPackage.ingredient.Ingredient.suppliers, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: myPackage.ingredient.Ingredient.suppliers, could not initialize proxy - no Session (through reference chain: myPackage.supplier.SupplierObject[\"ingredients\"]->org.hibernate.collection.internal.PersistentBag[0]->myPackage.ingredient.Ingredient[\"suppliers\"])"

我遵循了这一点:

避免在未获取的惰性对象上进行Jackson序列化

现在我没有错误,但是在返回的json中,Ingredients字段为null:

Now I haven't the error but in json returned, the ingredients field is null:

{
  "id": 1,
  "email": "mail@gmail.com",
  "phoneNumber": null,
  "address": null,
  "responsible": null,
  "companyName": "Company name",
  "vat": "vat number",
  "ingredients": null
}

但是在调试中我可以看到成分....

but in debug I can see ingredients....

推荐答案

这是Hibernate和Jackson Marshaller的正常行为 基本上,您希望具有以下内容:具有所有Supplier对象详细信息的JSON ...包括成分.

This is the normal behaviour of Hibernate and Jackson Marshaller Basically you want to have the following: a JSON with all Supplier object details... included the Ingredients.

请注意,在这种情况下,您必须非常小心,因为在尝试创建JSON本身时可以使用循环引用,因此也应使用

Please note that in this case you must be very carefull because you can have a cyclic reference when you try to create the JSON itself so you should use also JsonIgnore annotation

您必须做的第一件事是加载供应商及其所有详细信息(包括成分).

The first thing you must do is to load the Supplier and all its details (ingredients included).

您该怎么做?通过使用几种策略...让我们使用 Hibernate.initialize . 必须在DAO(或存储库)实现中的休眠会话关闭之前使用(基本上是在使用休眠会话的位置).

How can you do it? By using several strategies... let's use the Hibernate.initialize. This must be used before the closing of hibernate session that is in the DAO (or repository) implementation (basically where you use the hibernate session).

因此,在这种情况下(我假设使用Hibernate),在我的存储库类中,我应该写这样的东西:

So in this case (I assume to use Hibernate) in my repository class I should write something like this:

public Supplier findByKey(Long id)
{
    Supplier result = (Supplier) getSession().find(Supplier.class, id);
    Hibernate.initialize(result.getIngredients());
    return result;
}

现在您有了Supplier对象及其所有详细信息(Ingredients也是) 现在,在您的服务中,您可以执行以下操作:

Now you have the Supplier object with all its own details (Ingredients too) Now in your service you can do what you did that is:

@RequestMapping(value = "/{supplierId:[0-9]+}", method = RequestMethod.GET)
@ResponseStatus(value = HttpStatus.OK)
@ResponseBody
public SupplierObject get(@PathVariable Long supplierId) 
{
    Supplier supplier = supplierService.get(supplierId);
    SupplierObject supplierObject = new SupplierObject (supplier);
    return SupplierObject;
}

通过这种方式,Jackson能够编写JSON but,让我们看一下Ingredient对象.它具有以下属性:

In this way Jackson is able in writing the JSON but let's give a look to the Ingredient object.. it has the following property:

@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();

当Jackson尝试创建JSON时会发生什么?它将访问List<Ingredient>中的每个元素,并且还将尝试为此创建一个JSON ....也用于供应商列表,这是一个循环引用...所以您必须避免使用它,并且可以通过使用JsonIgnore批注避免这种情况.例如,您可以通过以下方式编写Ingredient实体类:

What will happen when Jackson tries to create the JSON? It will access to the each element inside the List<Ingredient> and it will try to create a JSON for this one too.... also for the suppliers list and this is a cyclic reference... so you must avoid it and you can avoid it by using the JsonIgnore annotation. For example you may write your Ingredient entity class in this way:

@JsonIgnoreProperties(value= {"suppliers"})
public class Ingredient implements Serializable
{
......
}

通过这种方式,您:

  • 将所有相关成分装入供应商对象
  • 在尝试创建JSON本身时避免循环引用

无论如何,我建议您创建特定的DTO(或VO)对象以用于编组和解组JSON

In any case I would suggest to you to create specific DTO (or VO) object to use for marshalling and unmarshalling JSONs

我希望这是有用的

安吉洛

这篇关于无法编写JSON:无法延迟初始化角色集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆