Nenhum serializador encontrado para a classe org.hibernate.proxy.pojo.javassist.Javassist?


94

Estou trabalhando em SpringMVC, Hibernate& JSONmas estou recebendo este erro.

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

Por favor, verifique minha entidade abaixo

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

    }

Como posso resolver isso?


Por favor, mostre o stacktrace e o código onde a exceção ocorre
geoand

Sem ter nenhum conhecimento do que seu código está tentando fazer, é um pouco difícil de depurar, mas você provavelmente vai querer verificar github.com/FasterXML/jackson-datatype-hibernate, já que você está usando Jackson e Hibernate
geoand

Você está tentando fazer um JSON desta classe? Nesse caso, o serializador JSON tenta gravar todas as propriedades, também o HashSet de seus relacionamentos muitos para muitos; isso cria uma exceção de inicializador lento
Angelo Immediata

a mesma pergunta pode ser encontrada em stackoverflow.com/questions/4362104/…
Matrix Buster

@ user2963481 ... Pergunta agradável e muito útil, irmão.
Cérebro

Respostas:


192

Tive um problema semelhante com o carregamento lento por meio do objeto proxy de hibernação. Contorne isso anotando a classe com propriedades privadas carregadas lentamente com:

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

Presumo que você pode adicionar as propriedades em seu objeto de proxy que interrompe a serialização JSON para essa anotação.

O problema é que as entidades são carregadas lentamente e a serialização ocorre antes de serem carregadas totalmente.

Hibernate.initialize(<your getter method>);

3
Funcionou para mim também ... Existe alguma explicação para esse comportamento estranho?
Victor,

7
@ ankur-singhal você deve enfatizar que esta anotação é necessária na classe aninhada e NÃO na classe de chamada.
Darwayne,

1
Yahooo ... funcionou. Tentei algumas vezes e funcionou. Tentei algumas maneiras e BoooM. Trabalhou.
Cérebro

2
Obrigado funcionou para mim também. Você precisa adicionar esta anotação às entidades que acessam outras entidades que possuem beans carregados lentamente.
Shafqat Shafi

3
Acho que essa não é a solução certa para o problema. Quando serializamos, esperamos que o subobjeto completo ou pelo menos a chave primária do subobjeto seja retornado no resultado. Adicionar essas anotações apenas suprimirá o erro, mas não fornecerá os resultados desejados.
Anand Vaidya

84

Só para acrescentar, encontrei o mesmo problema, mas as respostas fornecidas não funcionaram. Eu consertei pegando a sugestão da exceção e adicionando ao arquivo application.properties ...

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

Estou usando Spring Boot v1.3 com Hibernate 4.3

Ele agora serializa o objeto inteiro e os objetos aninhados.

EDIT: 2018

Como isso ainda recebe comentários vou esclarecer aqui. Isso absolutamente apenas esconde o erro. As implicações de desempenho estão aí. Na época, eu precisava de algo para entregar e trabalhar nisso mais tarde (o que fiz através de não usar mais a mola). Então, sim, ouça outra pessoa se você realmente quiser resolver o problema. Se você apenas quer que isso acabe, vá em frente e use esta resposta. É uma ideia terrível, mas, diabos, pode funcionar para você. Só para constar, nunca mais tive um acidente ou problema depois disso. Mas é provavelmente a origem do que acabou sendo um pesadelo de desempenho do SQL.


8
Resolve o problema, mas json conterá duas propriedades extras desnecessárias"handler":{},"hibernateLazyInitializer":{}
prettyvoid

ótimo! corrigido aqui também, esta é a resposta
Hinotori,

@prettyvoid Por que existem propriedades extras?
Robert Moon

12
@RobertMoon Se você quiser se livrar deles, você pode anotar sua entidade com@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
prettyvoid

@prettyvoid Obrigado. Eu encontrei outra solução é mudar LAZY para EAGER. Isso afeta a performance?
Robert Moon

68

Como sugerido corretamente nas respostas anteriores, o carregamento lento significa que, quando você busca seu objeto do banco de dados, os objetos aninhados não são buscados (e podem ser buscados posteriormente, quando necessário).

Agora Jackson tenta serializar o objeto aninhado (== fazer JSON dele), mas falha ao encontrar JavassistLazyInitializer em vez do objeto normal. Este é o erro que você vê. Agora, como resolver isso?

Conforme sugerido pelo CP510 anteriormente, uma opção é suprimir o erro por esta linha de configuração:

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

Mas isso é lidar com os sintomas, não com a causa . Para resolvê-lo com elegância, você precisa decidir se precisa ou não desse objeto em JSON?

  1. Se você precisar do objeto em JSON, remova a FetchType.LAZYopção do campo que o causa (também pode ser um campo em algum objeto aninhado, não apenas na entidade raiz que você está buscando).

  2. Se não precisar do objeto em JSON, anote o getter deste campo (ou o próprio campo, se também não precisar aceitar valores de entrada) com @JsonIgnore, por exemplo:

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

Se você tiver necessidades mais complexas (por exemplo, regras diferentes para controladores REST diferentes usando a mesma entidade), você pode usar visualizações ou filtragem jackson ou, para casos de uso muito simples, buscar objetos aninhados separadamente.


15
Esta é a melhor resposta. Aborde a raiz do problema, não apenas mascare os sintomas para o próximo programador ter que lidar.
Andrew

2
Você é meu herói.
Lay Leangsros

muito obrigado por explicar o motivo do erro e fornecer duas soluções que fazem sentido
Mauricio Poppe

Obrigado por isso, no entanto, vejo que springfox-swagger ainda me dá erroRangeError: Maximum call stack size exceeded
Pra_A

18

Você pode usar o módulo adicional para Jackson que lida com o carregamento lento do Hibernate.

Mais informações em https://github.com/FasterXML/jackson-datatype-hibernate que suportam hibernate 3 e 4 separadamente.


7
Esta deve ser realmente a resposta correta. Todas as outras respostas estão ocultando o problema, em vez de resolvê-lo.
Ahmed Hassanien

Mas como usar este módulo? existe algum guia para isso?
Anand Vaidya

Maneiras de configurar jackson-datatype-hibernate: stackoverflow.com/q/33727017
Chase

13

Acho que o problema é a maneira como você recupera a entidade.

Talvez você esteja fazendo algo assim:

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

Tente usar o método em getvez deload

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

O problema é que com o método load você obtém apenas um proxy, mas não o objeto real. O objeto proxy não possui as propriedades já carregadas, portanto, quando a serialização ocorre, não há propriedades a serem serializadas. Com o método get, você realmente obtém o objeto real, esse objeto poderia de fato ser serializado.


2
Um erro muito semelhante aconteceu comigo quando usei getOne em vez de findOne. No meu caso, meu repositório de interface estava estendendo JpaRepository. findOne funcionou bem sem quaisquer anotações Json ou alterações em application.properties
James Freitas

Como James Freitas, também descobri que getOne levou ao problema e, em vez disso, usar, por exemplo, findById - resolveu o problema sem a necessidade de usar a anotação ou a linha fornecida acima nas propriedades do aplicativo
MEU

1
Meu colega de trabalho me esclareceu e disse que: "A diferença básica é que getOne carrega lentamente e findOne não" - significando obviamente que o primeiro não obtém linhas de dados do banco de dados, mas apenas cria referências. Este último, em vez disso, obtém linhas, que é o caso que geralmente é desejado
MEU

@JamesFreitas YES! Obrigado! E obrigado Carlos por levar James a esta bela conclusão!
Filip Savic

9

funciona para mim

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

por exemplo

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

}

5

Existem duas maneiras de resolver o problema.

Caminho 1 :

Adicionar spring.jackson.serialization.fail-on-empty-beans=falseem application.properties

Caminho 2 :

Use join fetchna consulta JPQL para recuperar dados do objeto pai, veja abaixo:

@Query(value = "select child from Child child join fetch child.parent Parent ",
           countQuery = "select count(*) from Child child join child.parent parent ")
public Page<Parent> findAll(Pageable pageable); 

Obrigado! A primeira solução é ótima!
Lucas Moyano Angelini

Caminho 1. Ótimo. Obrigado.
Lay Leangsros

3

Adicione esta anotação à classe de entidade (modelo) que funciona para mim para causar carregamento lento por meio do objeto proxy de hibernação.

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


2

Esta exceção

org.springframework.http.converter.HttpMessageNotWritableException

recebendo porque, espero que sim, você está enviando a saída de resposta como um objeto Serializable.
Este é um problema que ocorre na primavera. Para superar esse problema, envie o objeto POJO como saída de resposta.

Exemplo:

    @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

Aula POJO:

public class UserVO {

    private int Id;
    private String userName;
    private String emailId;
    private String phone;
    private Integer active;

//setter and getters

No controlador, converta os campos de objeto serilizáveis ​​em campos de classe POJO e retorne a classe pojo como saída.

         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.

Sim, estou fazendo o mesmo, mas mesmo fazendo o mesmo estou recebendo o mesmo erro, porque estou enviando dados associados a objetos que nada mais são do que definir classes de entidade
Pra_A

2

No Hibernate 5.2 e superior, você pode remover o proxy do Hibernate conforme abaixo, ele fornecerá o objeto real para que você possa serializá-lo corretamente:

Object unproxiedEntity = Hibernate.unproxy( proxy );

ele também chamará automaticamente de Hibernate.initializeantemão.
GMsoF

@Tim, deve ser adicionado antes da serialização json. O problema ocorre porque um objeto de proxy de hibernação foi encontrado durante a serialização, portanto, depois de removido, a serialização ficará bem. Se você estiver usando um controlador de mola, deverá fazê-lo antes do final do controlador.
GMsoF de

1

Para Hibernate, você pode usar o projeto jackson-datatype-hibernate para acomodar a serialização / desserialização JSON com objetos carregados lentamente.

Por exemplo,

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

Se eu usar isso, entendo can't parse JSON. Raw result:. Qualquer ajuda?
Pra_A

1

A solução é inspirada na solução abaixo da @marco. Eu também atualizei sua resposta com esses dados.

O problema aqui é sobre o carregamento lento dos subobjetos, onde Jackson só encontra proxies de hibernação, em vez de objetos completos.

Portanto, ficamos com duas opções - Suprimir a exceção, como feito acima na resposta mais votada aqui, ou certifique-se de que os objetos LazyLoad sejam carregados.

Se você escolher a última opção, a solução seria usar a biblioteca jackson-datatype e configurar a biblioteca para inicializar as dependências de carregamento lento antes da serialização.

Eu adicionei uma nova classe de configuração para fazer isso.

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

}

@Primarycertifica-se de que nenhuma outra configuração de Jackson seja usada para inicializar qualquer outro bean. @Beané como de costume. module.enable(Hibernate5Module.Feature.FORCE_LAZY_LOADING);é habilitar o carregamento lento das dependências.

Cuidado - observe o impacto no desempenho. às vezes, a busca EAGER ajuda, mas mesmo que você a torne ansiosa, ainda precisará desse código, porque os objetos proxy ainda existem para todos os outros mapeamentos, exceto@OneToOne

PS: Como um comentário geral, eu desencorajaria a prática de enviar objetos de dados inteiros de volta na resposta Json. Deve-se usar Dto's para essa comunicação e usar algum mapeador como mapstruct para mapeá-los. Isso o salva de brechas de segurança acidentais, bem como da exceção acima.


1

Tenho o mesmo problema agora. verifique se você corrige a busca no preguiçoso com um @jsonIQgnore

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="teachers")
@JsonIgnoreProperties("course")
Teacher teach;

Basta excluir o "(fetch = ...)" ou a anotação "@jsonIgnore" e vai funcionar

@ManyToOne
@JoinColumn(name="teachers")
@JsonIgnoreProperties("course")
Teacher teach;

0

Ou você pode configurar o mapeador como:

// configuração personalizada para carregamento lento

public static class HibernateLazyInitializerSerializer extends JsonSerializer<JavassistLazyInitializer> {

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

e configurar o mapeador:

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

0

Pode ser o relacionamento de entidade do Hibernate causando o problema ... simplesmente pare o carregamento lento dessa entidade relacionada ... por exemplo ... Resolvi abaixo definindo lazy = "false" para 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>

1
Por favor, informe em seu post que pode ser uma solução muito perigosa na aplicação da vida real.
Panurg

0

Eu mudei (na classe de modelo de anotação)

fetch = FetchType.LAZY

para

fetch = FetchType.EAGER

e funcionou de uma maneira bonita ...

Adoro.


5
Embora isso resolva o problema, é muito perigoso. Mudar a fetchestratégia em um modelo tem várias consequências no desempenho. Com essa mudança, você está trazendo muito mais dados do banco de dados. Pode ser uma solução válida, mas primeiro é necessário um estudo de desempenho.
João Menighin

1
Se você sabe que é modelo e não tem muitas entidades relacionadas, pode gastar um pouco de memória e desempenho para obter uma entidade completa. mas é bom saber que é sempre melhor usar o LAZY fetch
Sham Fiorin

0

Este é um problema com Jackson. Para evitar isso, instrua Jackson a não serializar relacionamento aninhado ou classe aninhada.

Veja o exemplo a seguir. Classe de endereço mapeada para as classes City , State e Country e o próprio Estado está apontando para Country e Country apontando para Region. Quando seus valores de endereço forem obtidos por meio da API REST de boot do Spring, você receberá o erro acima. Para evitar isso, basta serializar a classe mapeada (que reflete o nível um JSON) e ignorar os relacionamentos aninhados com @JsonIgnoreProperties(value = {"state"}), @JsonIgnoreProperties(value = {"country"})e @JsonIgnoreProperties(value = {"region"})

Isso evitará a exceção Lazyload junto com o erro acima. Use o código abaixo como exemplo e mude suas classes de modelo.

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

-5

Experimentar

implements interface Serializable

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.