Programing

org.hibernate.proxy.pojo.javassist.Javassist 클래스에 대한 시리얼 라이저가 없습니까?

lottogame 2020. 9. 22. 21:00
반응형

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에서이 개체가 필요한지 여부를 결정해야합니까?

  1. JSON 형식의 개체가 필요한 경우 FetchType.LAZY원인이되는 필드 에서 옵션을 제거합니다 (가져 오는 루트 엔터티뿐만 아니라 일부 중첩 개체의 필드 일 수도 있음).

  2. 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

참고 URL : https://stackoverflow.com/questions/24994440/no-serializer-found-for-class-org-hibernate-proxy-pojo-javassist-javassist

반응형