序列化 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 时抛出了以下断言,它使我遇到了一个奇怪的问题