JSON을 쓸 수 없습니다. 역할 컬렉션을 게으르게 초기화하지 못했습니다.
JSON을 반환하는 Java, Hibernate, Spring으로 REST 서비스를 구현하려고 했습니다.
저는 많은 관계를 가지고 있습니다.저는 재료 목록을 가지고 있는 공급자가 있고, 각 재료는 공급자 목록을 가지고 있습니다.
테이블을 만들었습니다.
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;
}
....
공급업체 개체
@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();
}
}
및 Id 추상 개체
public abstract class IdAbstractObject{
public Long id;
}
문제는 엔드포인트를 호출할 때입니다.
http://localhost:8080/supplier/1
오류가 발생했습니다.
"JSON을 쓸 수 없습니다. 역할 모음인 myPackage를 게으르게 초기화하지 못했습니다.재료.구성 요소.공급자, 프록시를 초기화할 수 없습니다. 세션이 없습니다. 중첩 예외는 com.fasterxml.jackson.databind입니다.JsonMappingException: 역할 컬렉션 myPackage를 게으르게 초기화하지 못했습니다.재료.구성 요소.공급업체, 프록시를 초기화할 수 없습니다.
- 세션이 없습니다(참조 체인: myPackage를 통해).공급자.공급업체 개체["성분"]->org.hibernate.collection.내부의.persistentBag[0]->myPackage.재료.성분["공급업체"])"
나는 이것을 따랐습니다.
가져오지 않은 게으른 개체에 대한 Jackson 직렬화 방지
이제 오류는 없지만 json에서 반환된 성분 필드는 null입니다.
{
"id": 1,
"email": "mail@gmail.com",
"phoneNumber": null,
"address": null,
"responsible": null,
"companyName": "Company name",
"vat": "vat number",
"ingredients": null
}
하지만 디버그에서 나는 재료를 볼 수 있습니다...
이것은 Hibernate 및 Jackson Marshaller의 일반적인 동작입니다. 기본적으로 당신은 모든 공급업체 개체 세부 정보를 가진 JSON을 원합니다.재료를 포함했습니다.
이 경우 JSON 자체를 만들 때 주기적인 참조를 가질 수 있으므로 주의해야 합니다. 따라서 주석도 사용해야 합니다.
먼저 공급업체와 공급업체의 모든 세부 정보(성분 포함)를 로드해야 합니다.
어떻게 할 수 있죠?몇 가지 전략을 사용하여...를 사용합니다.DAO(또는 리포지토리) 구현(기본적으로 최대 절전 모드 세션을 사용하는 경우)에 있는 최대 절전 모드 세션을 닫기 전에 이 옵션을 사용해야 합니다.
따라서 이 경우(Hibernate를 사용하는 것으로 가정함) 저장소 클래스에서 다음과 같은 내용을 작성해야 합니다.
public Supplier findByKey(Long id)
{
Supplier result = (Supplier) getSession().find(Supplier.class, id);
Hibernate.initialize(result.getIngredients());
return result;
}
이제 당신이 가지고 있습니다.Supplier
세부 정보를 (자체부세개정포는체하함모두보를▁with개(▁object체자는▁(▁all하▁its)Ingredients
또한) 이제 서비스에서 다음과 같은 작업을 수행할 수 있습니다.
@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;
}
이런 식으로 잭슨은 JSON을 작성할 수 있습니다.but
을 살펴봅시다.Ingredient
속성을 .다음과 같은 속성을 가집니다.
@ManyToMany(mappedBy = "ingredients")
@OrderBy("created DESC")
@BatchSize(size = 1000)
private List<Supplier> suppliers = new ArrayList<>();
잭슨이 JSON을 만들려고 하면 어떻게 될까요?은 내의각요액다니합 안에 각 입니다.List<Ingredient>
도 마찬가지이며 입니다.공업체 목록급참인조다니입적주기. 은 그것을 주석을 하면 피할 수 .따라서 이를 피해야 하며 JsonIgnore 주석을 사용하여 피할 수 있습니다.예를 들어, 당신은 당신의 것을 쓸 수 있습니다.Ingredient
엔티티 클래스는 다음과 같습니다.
@JsonIgnoreProperties(value= {"suppliers"})
public class Ingredient implements Serializable
{
......
}
이러한 방식으로 다음을 수행할 수 있습니다.
- 공급업체 개체에 모든 관련 성분을 적재합니다.
- JSON 자체를 생성하려고 할 때 순환 참조를 피합니다.
어떤 경우에도 JSON을 마샬링 및 마샬링 해제하는 데 사용할 특정 DTO(또는 VO) 개체를 생성할 것을 제안합니다.
이것이 유용하기를 바랍니다.
안젤로
이 문제를 해결하기 위한 몇 가지 솔루션이 있습니다.
- 사용할 수 있습니다.
@ManyToMany(fetch = FetchType.EAGER)
그러나 성능 측면에서 보면 EARGER 페치는 매우 좋지 않습니다.게다가, 일단 여러분이 열성적인 협회를 가지면, 여러분이 그것을 게으르게 만들 수 있는 방법은 없습니다.
- 사용할 수 있습니다.
@ManyToMany @Fetch(FetchMode.JOIN)
더 많은 정보: https://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/FetchMode.html
과 같은 때 할 수 .application.properties
파일 이름:
spring.jpa.open-in-view = false
제 프로젝트에서 저는 당신의 프로젝트와 같은 문제를 발견했습니다.문제는 데이터를 "1대 다수"로 읽을 때까지 세션이 이미 닫혔다는 것입니다.모든 데이터를 가져오려면 트랜잭션을 명시적으로 초기화하거나 사용해야 합니다.명시적인 초기화를 사용했습니다.DAO에 줄을 추가해야 합니다.
Hibernate.initialize(supplier.getIngredients());
그런 다음 최대 절전 모드에서 데이터베이스의 모든 데이터를 로드합니다.할 때 을 추가합니다.@JsonIgnore
1대 다 모델 필드의 주석입니다.
다음은 내 코드의 예입니다.
1.모델
@OneToMany(mappedBy = "commandByEv", fetch = FetchType.LAZY)
@JsonIgnore
private Set<Evaluation> evaluations;
DAO
public Command getCommand(long id) {
Session session = sessionFactory.getCurrentSession();
Evaluation evaluation = session.get(Evaluation.class, id);
Hibernate.initialize(evaluation.getCommand());
return evaluation.getCommand();
}
그냥추를 추가하세요.@JsonIgnore
나고끝 @oneToMany
당신의 모델 수업에서.
Jackson-data type-hibernate를 사용해야 합니다.
https://github.com/FasterXML/jackson-datatype-hibernate
Application.java에 추가합니다.
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Hibernate5Module());
return objectMapper;
}
이는 유휴 초기화가 시작되기 전에 최대 절전 모드 세션이 닫혔기 때문입니다.
솔루션은 아래의 이 답변에서 잘 설명되어 있습니다.가져오지 않은 게으른 개체에 대한 Jackson 직렬화 방지
내 application.properties에서 spring jpa의 open-in-view 속성이 false였습니다.저는 이걸 없애기 위해 댓글을 달아야 했습니다.
#spring.jpa.open-in-view=false
이것이 누군가에게 도움이 되길 바랍니다.
추가해야 했습니다.spring.jpa.open-in-view = true
application.properties에
언급URL : https://stackoverflow.com/questions/48117059/could-not-write-json-failed-to-lazily-initialize-a-collection-of-role
'programing' 카테고리의 다른 글
PARTITION BY 1은 무엇을 의미합니까? (0) | 2023.07.26 |
---|---|
((보이드(*)0x1000)();'는 무슨 뜻입니까? (0) | 2023.07.26 |
MariaDB 커넥터 vs MySQLDB 커넥터 - 트랜잭션 문제 (0) | 2023.07.21 |
스프링 부트를 사용하여 Zuul에 대한 디버그 정보를 보려면 어떻게 해야 합니까? (0) | 2023.07.21 |
MySQL 파티셔닝을 생성한 후 이를 활용하려면 특수 쿼리가 필요합니까? (0) | 2023.07.21 |