Подтвердить что ты не робот

Сепаратор не найден для класса 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;
    }

    }

Как я могу решить эту проблему?

4b9b3361

Ответ 1

У меня была похожая проблема с отложенной загрузкой через прокси-объект hibernate. Обошел его, аннотируя класс с лениво загруженными частными свойствами с помощью:

@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})

Я предполагаю, что вы можете добавить свойства к вашему прокси-объекту, который нарушает сериализацию JSON к этой аннотации.

Проблема в том, что объекты загружаются лениво, и сериализация происходит до того, как они будут загружены полностью.

Hibernate.initialize(<your getter method>);

Ответ 2

Просто чтобы добавить это, я столкнулся с той же самой проблемой, но предоставленные ответы не работали. Я исправил это, приняв предложение об исключении и добавив в файл application.properties...

spring.jackson.serialization.fail-on-empty-beans=false

Я использую Spring Boot v1.3 с Hibernate 4.3

Теперь он сериализует весь объект и вложенные объекты.

РЕДАКТИРОВАТЬ: 2018

Поскольку это все еще получает комментарии, я уточню здесь. Это абсолютно только скрывает ошибку. Производительность влияет там. В то время мне нужно было что-то доставить и поработать над этим позже (что я и сделал, не используя пружину больше). Так что да, слушайте кого-то другого, если вы действительно хотите решить проблему. Если вы просто хотите, чтобы все прошло, используйте этот ответ. Это ужасная идея, но, черт возьми, это может сработать для вас. Для записи, никогда не было сбоев или проблем снова после этого. Но это, вероятно, источник того, что в итоге превратилось в кошмар производительности SQL.

Ответ 3

Как правильно сказано в предыдущих ответах, ленивая загрузка означает, что при извлечении вашего объекта из базы данных вложенные объекты не извлекаются (и могут появляться позже, когда это необходимо).

Теперь Джексон пытается сериализовать вложенный объект (== сделать JSON из него), но не удается, поскольку находит JavassistLazyInitializer вместо обычного объекта. Это ошибка, которую вы видите. Теперь, как его решить?

Как было предложено ранее CP510, одним из вариантов является подавление этой строки конфигурации:

spring.jackson.serialization.fail-on-empty-beans=false

Но это , касающееся симптомов, а не причины. Чтобы решить эту проблему элегантно, вам нужно решить, нужен ли вам этот объект в JSON или нет?

  • Если вам нужен объект в JSON, удалите параметр FetchType.LAZY из поля, которое его вызывает (это может быть поле в каком-либо вложенном объекте, а не только в корневой объект, который вы извлекаете).

  • Если не нужен объект в JSON, аннотируйте получателя этого поля (или самого поля, если вам тоже не нужно принимать входящие значения) с помощью @JsonIgnore, например:

    // this field will not be serialized to/from JSON @JsonIgnore private NestedType secret;

Если у вас есть более сложные потребности (например, разные правила для разных контроллеров REST с использованием одного и того же объекта), вы можете использовать jackson views или фильтрация или для очень простого варианта использования, вставляйте вложенные объекты отдельно.

Ответ 4

Вы можете использовать дополнительный модуль для Jackson, который обрабатывает Hibernate lazy-load.

Дополнительная информация о https://github.com/FasterXML/jackson-datatype-hibernate, которые поддерживают hibernate 3 и 4 отдельно.

Ответ 5

Я думаю, что проблема заключается в том, как вы извлекаете объект.

Возможно, вы делаете что-то вроде этого:

Person p = (Person) session.load(Person.class, new Integer(id));

Попробуйте использовать метод get вместо load

Person p = (Person) session.get(Person.class, new Integer(id));

Проблема заключается в том, что с помощью метода load вы получаете только прокси-сервер, но не реальный объект. Объект прокси не имеет уже загруженных свойств, поэтому, когда происходит сериализация, нет свойств для сериализации. С помощью метода get вы фактически получаете реальный объект, этот объект действительно может быть сериализован.

Ответ 6

Добавьте эту аннотацию к Entity Class (Model), которая работает для меня, это вызывает ленивую загрузку через прокси-объект hibernate.

@JsonIgnoreProperties ({"hibernateLazyInitializer", "handler"})

Ответ 7

меня устраивает

@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;

}

Ответ 8

Это исключение

org.springframework.http.converter.HttpMessageNotWritableException

потому что, я надеюсь, вы отправляете выходные данные в виде объекта Serializable.
Это проблема, возникающая spring. Чтобы преодолеть эту проблему, отправьте объект 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.

Ответ 9

В Hibernate 5.2 и выше вы можете удалить прокси-сервер hibernate, как показано ниже, он даст вам реальный объект, чтобы вы могли правильно его сериализовать:

Object unproxiedEntity = Hibernate.unproxy( proxy );

Ответ 10

Для 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;
    }
}

Ответ 11

Решение вдохновлено приведенным ниже решением @marco. Я также обновил его ответ этими данными.

Проблема здесь заключается в ленивой загрузке подобъектов, где Джексон находит только прокси гибернации, а не полноразмерные объекты.

Таким образом, у нас остается две опции: подавить исключение, как это было сделано выше в ответе с наибольшим количеством голосов, или убедиться, что объекты 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 как обычно. module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING); это включить отложенную загрузку зависимостей.

Внимание - Пожалуйста, следите за его влиянием на производительность. иногда помогает EAGER fetch, но даже если вы сделаете его активным, вам все равно понадобится этот код, потому что прокси-объекты все еще существуют для всех других отображений, кроме @OneToOne

PS: В качестве общего комментария я бы не рекомендовал отправлять весь объект данных обратно в ответ Json. Для этого следует использовать Dto, а для отображения их использовать какой-то картограф, например mapstruct. Это спасает вас от случайных лазеек в безопасности, а также исключений, указанных выше.

Ответ 12

Или вы можете настроить mapper как:

//настраиваемая конфигурация для ленивой загрузки

public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> {

    @Override
    public void serialize(JavassistLazyInitializer initializer, JsonGenerator jsonGenerator,
            SerializerProvider serializerProvider)
            throws IOException, JsonProcessingException {
        jsonGenerator.writeNull();
    }
}

и сконфигурируйте mapper:

    mapper = new JacksonMapper();
    SimpleModule simpleModule = new SimpleModule(
            "SimpleModule", new Version(1,0,0,null)
    );
    simpleModule.addSerializer(
            JavassistLazyInitializer.class,
            new HibernateLazyInitializerSerializer()
    );
    mapper.registerModule(simpleModule);

Ответ 13

Это может быть ваша связь с сущностью Hibernate, вызывающая проблему... просто прекратите ленивую загрузку этого связанного объекта... например... Я решил ниже, установив lazy = "false" для customerType.

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

Ответ 14

Я изменился (в классе модели Аннотации)

fetch = FetchType.LAZY

в

fetch = FetchType.EAGER

и работал довольно хорошо...

Любить это.

Ответ 15

Это проблема с Джексоном. Чтобы предотвратить это, проинструктируйте Джексона не сериализовать вложенные отношения или вложенный класс.

Посмотрите на следующий пример. Класс адресов сопоставляется с классами City, State и Country, а само State указывает на Country, а Country указывает на Region. Когда вы получите значения адресов через Spring REST API, вы получите сообщение об ошибке выше. Чтобы предотвратить это, просто сериализуйте сопоставленный класс (который отражает уровень 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;
}

Ответ 16

Попробуйте

implements interface Serializable