序列化 Hibernate 对象时抛出奇怪的 Jackson 异常

Posted

技术标签:

【中文标题】序列化 Hibernate 对象时抛出奇怪的 Jackson 异常【英文标题】:Strange Jackson exception being thrown when serializing Hibernate object 【发布时间】:2011-05-20 17:05:38 【问题描述】:

Jackson 抛出了一个我不知道如何解决的奇怪异常。我正在使用 Spring、Hibernate 和 Jackson。

我已经考虑过延迟加载导致问题,但我已采取措施告诉杰克逊不要处理各种属性,如下所示:

@JsonIgnoreProperties( "sentMessages", "receivedMessages", "educationFacility" )
public class Director extends UserAccount implements EducationFacilityUser 
   ....

我对所有其他 UserAccount 子类也做了同样的事情。

抛出的异常如下:

org.codehaus.jackson.map.JsonMappingException: No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS) ) (through reference chain: java.util.ArrayList[46]->jobprep.domain.educationfacility.Director_$$_javassist_2["handler"])
    at org.codehaus.jackson.map.ser.StdSerializerProvider$1.serialize(StdSerializerProvider.java:62)
    at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:268)
    at org.codehaus.jackson.map.ser.BeanSerializer.serializeFields(BeanSerializer.java:146)
    at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:118)
    at org.codehaus.jackson.map.ser.ContainerSerializers$IndexedListSerializer.serializeContents(ContainerSerializers.java:236)
    at org.codehaus.jackson.map.ser.ContainerSerializers$IndexedListSerializer.serializeContents(ContainerSerializers.java:189)
    at org.codehaus.jackson.map.ser.ContainerSerializers$AsArraySerializer.serialize(ContainerSerializers.java:111)
    at org.codehaus.jackson.map.ser.StdSerializerProvider._serializeValue(StdSerializerProvider.java:296)
    at org.codehaus.jackson.map.ser.StdSerializerProvider.serializeValue(StdSerializerProvider.java:224)
    at org.codehaus.jackson.map.ObjectMapper.writeValue(ObjectMapper.java:925)
    at org.springframework.http.converter.json.MappingJacksonHttpMessageConverter.writeInternal(MappingJacksonHttpMessageConverter.java:153)

关于如何获取更多信息以了解导致此问题的原因的建议?有人知道怎么解决吗?

编辑: 我发现代理对象上存在 getHander() 和其他 get*() 方法。 GRR!!有什么办法可以告诉杰克逊不要在代理上处理任何东西,或者我可以吗?这真的很奇怪,因为吐出 JSON 的方法只会在某些情况下崩溃,而不是一直崩溃。尽管如此,这是由于代理对象上的 get*() 方法造成的。

旁白:代理是邪恶的。它们破坏了 Jackson、equals() 和常规 Java 编程的许多其他部分。我很想完全放弃 Hibernate:/

【问题讨论】:

你是否从控制器返回了一个 Director 类型的对象? @btiernay:看起来像,是的。好消息是大图非常擅长解决这些问题。 @skaffman:我正在返回所有 UserAccount 类型的列表,其中一个是 Director...所以是的。 @btiernay:我不知道这是否与 Jira 有关。这是一个错误,还是它应该如何工作?如果有的话,我认为这是 Hibernate 的错。或者是吗?我不知道。我只想把它修好:( 对我来说,解决方案只是添加 OhadR 提到的适当的 getter 和 setter。 【参考方案1】:

我在通过休眠代理对象延迟加载时遇到了类似的问题。通过注释具有延迟加载私有属性的类来解决它:

@JsonIgnoreProperties("hibernateLazyInitializer", "handler")

我假设您可以在代理对象上添加打破 JSON 序列化到该注释的属性。

Avoid Jackson serialization on non fetched lazy objects

【讨论】:

就我而言,例外是关于惰性代理,但它具有误导性。从调试器中,我看到当它尝试序列化名为handler 的属性时引发了异常。添加此注释自然会阻止杰克逊尝试对其进行序列化。就在现场!非常感谢!【参考方案2】:

这并不理想,但您可以禁用 Jackson 对 JSON 属性的自动发现,在类级别使用 @JsonAutoDetect。这将阻止它尝试处理 Javassist 的东西(并失败)。

这意味着您必须手动注释每个 getter(使用 @JsonProperty),但这不一定是坏事,因为它使事情变得明确。

【讨论】:

是的,我就是这么做的。我猜这还不错,但它让我的一些课程有点臃肿,到处都是注释。估计没办法了。 @egervari:这是未来的方式,你知道,就像银色西装和机器人一样。 对于它的价值,您还可以使用混合注释(wiki.fasterxml.com/JacksonMixInAnnotations)将注释分开;不是更轻,但更清洁。 @egervari 如何使用@JsonAutoDetect 禁用 JSON 属性的自动发现? 您可以通过 @JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAudtoDetect.Visibility.NONE) 禁用杰克逊自动发现【参考方案3】:

我遇到了同样的错误,但与 Hibernate 无关。我被所有可怕的建议吓到了,我想这在休眠和延迟加载的情况下是相关的...... 但是,在我的情况下,我得到了错误,因为在内部类中我没有 getter/setter,所以 BeanSerializer 无法序列化数据......

添加 getter 和 setter 解决了这个问题。

【讨论】:

这对我很有帮助! 我该如何反其道而行之? IE。我不想添加 getter/setter,但我希望 Jackson 跳过该属性。【参考方案4】:

值得一提的是,Jackson Hibernate module 项目刚刚开始,应该可以解决这个问题,希望也能解决其他问题。 项目与杰克逊项目有关,但不是核心源代码的一部分。这主要是为了允许更简单的发布过程;它将需要 Jackson 1.7,因为那是引入 Module API 的时候。

【讨论】:

【参考方案5】:

我遇到了同样的问题。看看你是否使用hibernatesession.load()。如果是这样,请尝试转换为hibernatesession.get()。这解决了我的问题。

【讨论】:

这正是我的代码出了问题。谢谢。【参考方案6】:

我收到了来自 spring 的 @RestController 的相同错误消息。我的休息控制器类使用弹簧的JpaRepository 类,并通过用repository.findOne(id) 替换repository.getOne(id) 方法调用,问题就消失了。

【讨论】:

@Sllouyssgortyou 可以查看我对 Spring Boot 解决方案的回答。 ***.com/a/36704716/1577363【参考方案7】:

与其他答案类似,我的问题是声明一个多对一列来进行延迟获取。切换到渴望获取解决了这个问题。 之前:

@ManyToOne(targetEntity = StatusCode.class, fetch = FetchType.LAZY)

之后:

@ManyToOne(targetEntity = StatusCode.class, fetch = FetchType.EAGER)

【讨论】:

【参考方案8】:

你可以使用 jackson-datatype-hibernate 模块来解决这个问题。它对我有用。 参考:https://github.com/FasterXML/jackson-datatype-hibernate

【讨论】:

【参考方案9】:

我也遇到了同样的问题,这里是问候

Avoid Jackson serialization on non fetched lazy objects

http://blog.pastelstudios.com/2012/03/12/spring-3-1-hibernate-4-jackson-module-hibernate/

https://github.com/nessonqk/jackson-datatype-hibernate

【讨论】:

【参考方案10】:

你可以在你的类“Director”上使用@JsonIgnoreProperties(value = "handler", "hibernateLazyInitializer" )注解

【讨论】:

【参考方案11】:

您可以在 Object.class 上添加 Jackson mixin 以始终忽略与休眠相关的属性。如果您使用的是 Spring Boot,请将其放在您的 Application 类中:

@Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() 
    Jackson2ObjectMapperBuilder b = new Jackson2ObjectMapperBuilder();
    b.mixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
    return b;



@JsonIgnoreProperties("hibernateLazyInitializer", "handler")
private abstract class IgnoreHibernatePropertiesInJackson 

【讨论】:

【参考方案12】:

我是 Jackson API 的新手,当我收到“org.codehaus.jackson.map.JsonMappingException: No serializer found for class com.company.project.yourclass”时,我将 getter 和 setter 添加到 com.company。 project.yourclass,帮助我使用 ObjectMapper 的映射器对象将 java 对象写入平面文件。

【讨论】:

【参考方案13】:

我遇到了同样的问题,但奇怪的是,相同的代码在少数情况下有效,而在某些随机情况下却失败了。

我只是通过确保正确的 setter/getter 来解决它(确保区分大小写)

【讨论】:

【参考方案14】:

我试过@JsonDetect

@JsonIgnoreProperties(value = "handler", "hibernateLazyInitializer" )

它们都不适合我。使用第三方模块对我来说似乎是很多工作。所以我只是尝试在传递给jackson 进行序列化之前对惰性对象的任何属性进行get 调用。工作代码 sn-p 看起来像这样:

@RequestMapping(value = "/authenticate", produces = "application/json; charset=utf-8")
    @ResponseBody
    @Transactional
    public Account authenticate(Principal principal) 
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = (UsernamePasswordAuthenticationToken) principal;
        LoggedInUserDetails loggedInUserDetails = (LoggedInUserDetails) usernamePasswordAuthenticationToken.getPrincipal();
        User user = userRepository.findOne(loggedInUserDetails.getUserId());
        Account account = user.getAccount();
        account.getFullName();      //Since, account is lazy giving it directly to jackson for serlization didn't worked & hence, this quick-fix.
        return account;
    

【讨论】:

【参考方案15】:

您还可以将域对象 Director 设为最终版本。这不是完美的解决方案,但它会阻止创建域类的代理子类。

【讨论】:

以上是关于序列化 Hibernate 对象时抛出奇怪的 Jackson 异常的主要内容,如果未能解决你的问题,请参考以下文章

Spring / Hibernate - 删除实体时抛出 StaleStateException

我在 Flutter 中遇到了一个问题:在构建 TextField 时抛出了以下断言,它使我遇到了一个奇怪的问题

Multer在通过ng-file上传上传文件时抛出奇怪的错误

异常库

PouchDB 复制在复制时抛出错误

C# HttpClient 在没有成功状态代码时抛出异常 [关闭]