org.hibernate.proxy.pojo.javassist.Javassist 클래스에 대한 시리얼 라이저가 없습니까?
내가 일하고 SpringMVC
, Hibernate
& JSON
하지만 난이 오류를 얻고있다.
HTTP Status 500 - Could not write JSON: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.SerializationFeature.FAIL_ON_EMPTY_BEANS) )
아래 내 법인을 확인하십시오
@Entity
@Table(name="USERS")
public class User {
@Id
@GeneratedValue
@Column(name="USER_ID")
private Integer userId;
@Column(name="USER_FIRST_NAME")
private String firstName;
@Column(name="USER_LAST_NAME")
private String lastName;
@Column(name="USER_MIDDLE_NAME")
private String middleName;
@Column(name="USER_EMAIL_ID")
private String emailId;
@Column(name="USER_PHONE_NO")
private Integer phoneNo;
@Column(name="USER_PASSWORD")
private String password;
@Column(name="USER_CONF_PASSWORD")
private String confPassword;
@Transient
private String token;
@Column(name="USER_CREATED_ON")
private Date createdOn;
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
@Fetch(value = FetchMode.SUBSELECT)
@JoinTable(name = "USER_ROLES", joinColumns = { @JoinColumn(name = "USER_ID") }, inverseJoinColumns = { @JoinColumn(name = "ROLE_ID") })
private List<ActifioRoles> userRole = new ArrayList<ActifioRoles>();
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL,mappedBy="userDetails")
@Fetch(value = FetchMode.SUBSELECT)
private List<com.actifio.domain.Address> userAddress = new ArrayList<com.actifio.domain.Address>();
@OneToOne(cascade=CascadeType.ALL)
private Tenant tenantDetails;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getConfPassword() {
return confPassword;
}
public void setConfPassword(String confPassword) {
this.confPassword = confPassword;
}
public Date getCreatedOn() {
return createdOn;
}
public void setCreatedOn(Date createdOn) {
this.createdOn = createdOn;
}
public List<ActifioRoles> getUserRole() {
return userRole;
}
public void setUserRole(List<ActifioRoles> userRole) {
this.userRole = userRole;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
public Integer getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(Integer phoneNo) {
this.phoneNo = phoneNo;
}
public List<com.actifio.domain.Address> getUserAddress() {
return userAddress;
}
public void setUserAddress(List<com.actifio.domain.Address> userAddress) {
this.userAddress = userAddress;
}
public Tenant getTenantDetails() {
return tenantDetails;
}
public void setTenantDetails(Tenant tenantDetails) {
this.tenantDetails = tenantDetails;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
}
어떻게 해결할 수 있습니까?
최대 절전 모드 프록시 개체를 통한 지연로드와 비슷한 문제가있었습니다. 지연로드 된 개인 속성이있는 클래스에 다음과 같이 주석을 추가하여 문제를 해결했습니다.
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
JSON 직렬화를 해당 주석에 중단하는 프록시 개체의 속성을 추가 할 수 있다고 가정합니다.
문제는 엔티티가 느리게로드되고 완전히로드되기 전에 직렬화가 발생한다는 것입니다.
Hibernate.initialize(<your getter method>);
이것을 추가하기 위해 동일한 문제가 발생했지만 제공된 답변이 작동하지 않았습니다. 예외의 제안을 받아들이고 application.properties 파일에 추가하여 수정했습니다.
spring.jackson.serialization.fail-on-empty-beans=false
Hibernate 4.3과 함께 Spring Boot v1.3을 사용하고 있습니다.
이제 전체 개체와 중첩 된 개체를 직렬화합니다.
수정 : 2018
여전히 댓글이 있기 때문에 여기서 명확히하겠습니다. 이것은 절대적으로 오류를 숨 깁니다. 성능에 미치는 영향이 있습니다. 그 당시에는 나중에 전달하고 작업 할 무언가가 필요했습니다 (더 이상 봄을 사용하지 않고 수행했습니다). 예, 문제를 정말로 해결하고 싶다면 다른 사람의 말을 들어보세요. 지금 당장 사라지기를 원한다면이 답변을 사용하십시오. 끔찍한 생각이지만, 도대체 효과가있을 수 있습니다. 기록을 위해,이 후 다시 충돌이나 문제가 발생하지 않았습니다. 그러나 그것은 아마도 SQL 성능 악몽이 된 원인 일 것입니다.
이전 답변에서 올바르게 제안했듯이 지연로드는 데이터베이스에서 개체를 가져올 때 중첩 된 개체를 가져 오지 않음 (필요할 때 나중에 가져올 수 있음)을 의미합니다.
이제 Jackson은 중첩 된 객체를 직렬화하려고 시도하지만 (== JSON으로 만들기) 일반 객체 대신 JavassistLazyInitializer를 찾으면 실패합니다. 이것은 당신이 보는 오류입니다. 이제 어떻게 해결할까요?
이전에 CP510에서 제안한대로 한 가지 옵션은 다음 구성 줄에서 오류를 억제하는 것입니다.
spring.jackson.serialization.fail-on-empty-beans=false
그러나 이것은 원인이 아니라 증상을 다루는 것입니다 . 우아하게 해결하려면 JSON에서이 개체가 필요한지 여부를 결정해야합니까?
JSON 형식의 개체가 필요한 경우
FetchType.LAZY
원인이되는 필드 에서 옵션을 제거합니다 (가져 오는 루트 엔터티뿐만 아니라 일부 중첩 개체의 필드 일 수도 있음).JSON의 객체가 필요하지 않은 경우이 필드의 getter (또는 들어오는 값을 허용 할 필요가없는 경우 필드 자체)에 다음과 같이 주석을 추가합니다
@JsonIgnore
.// this field will not be serialized to/from JSON @JsonIgnore private NestedType secret;
더 복잡한 요구 사항 (예 : 동일한 엔티티를 사용하는 다른 REST 컨트롤러에 대한 다른 규칙)이있는 경우 jackson 보기 또는 필터링을 사용 하거나 매우 간단한 사용 사례의 경우 중첩 된 개체를 개별적으로 가져올 수 있습니다.
Hibernate lazy-loading을 처리하는 Jackson 용 애드온 모듈을 사용할 수 있습니다.
https://github.com/FasterXML/jackson-datatype-hibernate에 대한 자세한 정보는 최대 절전 모드 3과 4를 별도로 지원합니다.
문제는 엔티티를 검색하는 방식이라고 생각합니다.
아마도 다음과 같이 할 수 있습니다.
Person p = (Person) session.load(Person.class, new Integer(id));
get
대신 방법을 사용해보십시오.load
Person p = (Person) session.get(Person.class, new Integer(id));
문제는로드 방법을 사용하면 실제 객체가 아닌 프록시 만 얻을 수 있다는 것입니다. 프록시 객체에는 속성이 이미로드되어 있지 않으므로 직렬화가 발생하면 직렬화 할 속성이 없습니다. get 메서드를 사용하면 실제로 실제 개체를 얻을 수 있으며이 개체는 실제로 직렬화 될 수 있습니다.
그것은 나를 위해 작동합니다
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
예 :
@Entity
@Table(name = "user")
@Data
@NoArgsConstructor
@JsonIgnoreProperties({"hibernateLazyInitializer","handler"})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private Date created;
}
나를 위해 작동하는 엔티티 클래스 (모델) 에이 주석을 추가하면 최대 절전 모드 프록시 개체를 통한 지연 로딩이 발생합니다.
@JsonIgnoreProperties ({ "hibernateLazyInitializer", "handler"})
이 예외
org.springframework.http.converter.HttpMessageNotWritableException
나는 당신이 응답 출력을 Serializable 객체로 보내고 있기를 바랍니다.
이것은 봄에 발생하는 문제입니다. 이 문제를 해결하려면 POJO 객체를 응답 출력으로 보냅니다.
예 :
@Entity
@Table(name="user_details")
public class User implements Serializable{
@Id
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Column(name="id")
private Integer id;
@Column(name="user_name")
private String userName;
@Column(name="email_id")
private String emailId;
@Column(name="phone_no")
private String phone;
//setter and getters
POJO 클래스 :
public class UserVO {
private int Id;
private String userName;
private String emailId;
private String phone;
private Integer active;
//setter and getters
컨트롤러에서 serilizable 개체 필드를 POJO 클래스 필드로 변환하고 출력으로 pojo 클래스를 반환합니다.
User u= userService.getdetials(); // get data from database
UserVO userVo= new UserVO(); // created pojo class object
userVo.setId(u.getId());
userVo.setEmailId(u.getEmailId());
userVo.setActive(u.getActive());
userVo.setPhone(u.getPhone());
userVo.setUserName(u.getUserName());
retunr userVo; //finally send pojo object as output.
Hibernate 5.2 이상에서는 아래와 같이 hibernate 프록시를 제거 할 수 있으며, 제대로 직렬화 할 수 있도록 실제 객체를 제공합니다.
Object unproxiedEntity = Hibernate.unproxy( proxy );
Hibernate의 경우 jackson-datatype-hibernate 프로젝트를 사용하여 지연로드 된 객체로 JSON 직렬화 / 역 직렬화를 수용 할 수 있습니다 .
예를 들면
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JacksonDatatypeHibernate5Configuration {
// Register Jackson Hibernate5 Module to handle JSON serialization of lazy-loaded entities
// Any beans of type com.fasterxml.jackson.databind.Module are automatically
// registered with the auto-configured Jackson2ObjectMapperBuilder
// https://docs.spring.io/spring-boot/docs/current/reference/html/howto-spring-mvc.html#howto-customize-the-jackson-objectmapper
@Bean
public Module hibernate5Module() {
Hibernate5Module hibernate5Module = new Hibernate5Module();
hibernate5Module.enable( Hibernate5Module.Feature.FORCE_LAZY_LOADING );
hibernate5Module.disable( Hibernate5Module.Feature.USE_TRANSIENT_ANNOTATION );
return hibernate5Module;
}
}
이 솔루션은 @marco의 아래 솔루션에서 영감을 얻었습니다. 나는 또한 이러한 datails로 그의 답변을 업데이트했습니다.
여기서 문제는 하위 객체의 지연로드에 관한 것입니다. 여기서 Jackson은 완전히 끊어진 객체 대신 최대 절전 모드 프록시 만 찾습니다.
따라서 두 가지 옵션이 남아 있습니다. 위의 대부분의 투표 된 답변 에서처럼 예외를 억제하거나 LazyLoad 객체가로드되었는지 확인합니다.
후자의 옵션을 선택하는 경우 해결책은 jackson-datatype 라이브러리 를 사용 하고 직렬화 전에 지연로드 종속성을 초기화하도록 라이브러리를 구성하는 것입니다.
이를 위해 새 구성 클래스를 추가했습니다.
@Configuration
public class JacksonConfig extends WebMvcConfigurerAdapter {
@Bean
@Primary
public MappingJackson2HttpMessageConverter jacksonMessageConverter(){
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
Hibernate5Module module = new Hibernate5Module();
module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
mapper.registerModule(module);
messageConverter.setObjectMapper(mapper);
return messageConverter;
}
}
@Primary
다른 Bean을 초기화하는 데 다른 Jackson 구성이 사용되지 않도록합니다. @Bean
평소와 같습니다. module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);
종속성의 지연로드를 활성화하는 것입니다.
주의-성능에 미치는 영향을 확인하십시오. 때로는 EAGER fetch가 도움이되지만, 간절하게 만들더라도이 코드가 여전히 필요합니다. 프록시 개체는@OneToOne
추신 : 일반적인 의견으로 Json 응답에서 전체 데이터 객체를 다시 보내는 관행을 권장하지 않습니다. One은이 통신에 Dto를 사용해야하며 mapstruct와 같은 일부 매퍼를 사용하여 매핑해야합니다. 이는 위의 예외뿐만 아니라 우발적 인 보안 허점으로부터 당신을 구합니다.
또는 매퍼를 다음과 같이 구성 할 수 있습니다.
// 지연 로딩을위한 맞춤 구성
public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> {
@Override
public void serialize(JavassistLazyInitializer initializer, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
jsonGenerator.writeNull();
}
}
매퍼를 구성하십시오.
mapper = new JacksonMapper();
SimpleModule simpleModule = new SimpleModule(
"SimpleModule", new Version(1,0,0,null)
);
simpleModule.addSerializer(
JavassistLazyInitializer.class,
new HibernateLazyInitializerSerializer()
);
mapper.registerModule(simpleModule);
문제를 일으키는 Hibernate 엔티티 관계 일 수 있습니다. 관련 엔티티의 지연로드를 중지하기 만하면됩니다 ... 예를 들어 ... 저는 customerType에 대해 lazy = "false"를 설정하여 아래에서 해결했습니다.
<class name="Customer" table="CUSTOMER">
<id name="custId" type="long">
<column name="CUSTID" />
<generator class="assigned" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="phone" type="java.lang.String">
<column name="PHONE" />
</property>
<property name="pan" type="java.lang.String">
<column name="PAN" />
</property>
<many-to-one name="customerType" not-null="true" lazy="false"></many-to-one>
</class>
</hibernate-mapping>
(주석 모델 클래스에서) 변경했습니다.
fetch = FetchType.LAZY
에
fetch = FetchType.EAGER
그리고 예쁘게 일했습니다 ...
그것을 사랑하십시오.
이것은 Jackson의 문제입니다. 이를 방지하려면 Jackson에게 중첩 된 관계 나 중첩 된 클래스를 직렬화하지 않도록 지시하십시오.
다음 예를보십시오. City , State , Country 클래스에 매핑 된 Address 클래스 와 State 자체는 Region을 가리키는 Country 및 Country를 가리 킵니다. Spring boot REST API를 통해 주소 값을 가져 오면 위의 오류가 발생합니다. 이를 방지하려면 매핑 된 클래스 (레벨 1 JSON을 반영 함)를 직렬화하고 , 및@JsonIgnoreProperties(value = {"state"})
@JsonIgnoreProperties(value = {"country"})
@JsonIgnoreProperties(value = {"region"})
이것은 위의 오류와 함께 Lazyload 예외를 방지합니다. 아래 코드를 예제로 사용하고 모델 클래스를 변경하십시오.
Address.java
@Entity
public class Address extends AbstractAuditingEntity
{
private static final long serialVersionUID = 4203344613880544060L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "street_name")
private String streetName;
@Column(name = "apartment")
private String apartment;
@ManyToOne
@JoinColumn(name = "city_id")
@JsonIgnoreProperties(value = {"state"})
private City city;
@ManyToOne
@JoinColumn(name = "state_id")
@JsonIgnoreProperties(value = {"country"})
private State state;
@ManyToOne
@JoinColumn(name = "country_id")
@JsonIgnoreProperties(value = {"region"})
private Country country;
@ManyToOne
@JoinColumn(name = "region_id")
private Region region;
@Column(name = "zip_code")
private String zipCode;
@ManyToOne
@JoinColumn(name = "address_type_id", referencedColumnName = "id")
private AddressType addressType;
}
City.java
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "city")
@Cache(region = "cityCache",usage = CacheConcurrencyStrategy.READ_WRITE)
@Data
public class City extends AbstractAuditingEntity
{
private static final long serialVersionUID = -8825045541258851493L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
//@Length(max = 100,min = 2)
private String name;
@ManyToOne
@JoinColumn(name = "state_id")
private State state;
}
State.java
@Entity
@Table(name = "state")
@Data
@EqualsAndHashCode(callSuper = true)
public class State extends AbstractAuditingEntity
{
private static final long serialVersionUID = 5553856435782266275L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "code")
private String code;
@Column(name = "name")
@Length(max = 200, min = 2)
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "country_id")
private Country country;
}
Country.java
@Entity
@Table(name = "country")
@Data
@EqualsAndHashCode(callSuper = true)
public class Country extends AbstractAuditingEntity
{
private static final long serialVersionUID = 6396100319470393108L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
@Length(max = 200, min = 2)
private String name;
@Column(name = "code")
@Length(max = 3, min = 2)
private String code;
@Column(name = "iso_code")
@Length(max = 3, min = 2)
private String isoCode;
@ManyToOne
@JoinColumn(name = "region_id")
private Region region;
}
시험
implements interface Serializable
'Programing' 카테고리의 다른 글
appharbor에서 웹 서비스를 빌드 할 때 nuget.exe를 찾을 수 없습니다. (0) | 2020.09.22 |
---|---|
Ruby on Rails 3 OSX에서 '/tmp/mysql.sock'소켓을 통해 로컬 MySQL 서버에 연결할 수 없습니다. (0) | 2020.09.22 |
SQL Server 2005의 날짜 / 시간에서 월 및 연도 가져 오기 (0) | 2020.09.22 |
Ruby HEREDOC에서 선행 공백 문자를 제거하려면 어떻게해야합니까? (0) | 2020.09.22 |
Xcode 10, Command CodeSign이 0이 아닌 종료 코드로 실패했습니다. (0) | 2020.09.22 |