Spring JPA Json循环依赖的问题分析
Posted bladestone
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring JPA Json循环依赖的问题分析相关的知识,希望对你有一定的参考价值。
背景
Lombok中的@Data,其等价于:
setter/getter、equals、canEqual、hashCode、toString
在Spring Data JPA中,对于存在双向依赖的情况,类似如下:
@Entity
@Table(name="t_user")
@Data
public class User
private Long id;
private String name;
@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="user_ext_id", referencedColumnName="id")
private UserExtEntity userExtEntity;
@Entity
@Table(name="t_user")
@Data
public class UserExtEntity
private String info;
@OneToOne(mappedBy = "userExtEntity")
private UserEntity userEntity;
问题描述
测试代码:
@Test
public void testJsonInfinite()
List<UserEntity> userEntities = this.userRepository.findAll();
log.info("User entities:", Arrays.toString(userEntities.toArray()));
异常信息如下:
java.lang.StackOverflowError
at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.dtoa(FloatingDecimal.java:431)
at sun.misc.FloatingDecimal$BinaryToASCIIBuffer.access$100(FloatingDecimal.java:259)
at sun.misc.FloatingDecimal.getBinaryToASCIIConverter(FloatingDecimal.java:1825)
at sun.misc.FloatingDecimal.toJavaFormatString(FloatingDecimal.java:80)
at java.lang.Float.toString(Float.java:206)
at java.lang.Float.toString(Float.java:568)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserExtEntity.toString(UserExtEntity.java:16)
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at org.spb.data.dao.entity.UserExtEntity$HibernateProxy$OYDwMbzs.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserEntity.toString(UserEntity.java:23)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserExtEntity.toString(UserExtEntity.java:16)
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at org.spb.data.dao.entity.UserExtEntity$HibernateProxy$OYDwMbzs.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserEntity.toString(UserEntity.java:23)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserExtEntity.toString(UserExtEntity.java:16)
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at org.spb.data.dao.entity.UserExtEntity$HibernateProxy$OYDwMbzs.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserEntity.toString(UserEntity.java:23)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserExtEntity.toString(UserExtEntity.java:16)
at sun.reflect.GeneratedMethodAccessor38.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:56)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at org.spb.data.dao.entity.UserExtEntity$HibernateProxy$OYDwMbzs.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at org.spb.data.dao.entity.UserEntity.toString(UserEntity.java:23)
使用了解决循环依赖的策略:
- @JsonManagedReference/ @JsonBackReference
- @JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = “id”)
但是上述的问题依旧。 但是在简单的Case中是可以正常工作的.
解决办法
移除其中一个@Data方法,其中默认重写了@ToString的方法,导致上述的两个方法不起作用,从异常日志上看,应该是有Proxy代理相关的内容引发的。
解决的代码:
@Entity
@Table(name="t_user")
@Data
public class User
private Long id;
private String name;
@JsonManagedReference
@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name="user_ext_id", referencedColumnName="id")
private UserExtEntity userExtEntity;
@Entity
@Table(name="t_user")
@Getter
@Setter
public class UserExtEntity
private String info;
@JsonBackReference
@OneToOne(mappedBy = "userExtEntity")
private UserEntity userEntity;
以上是关于Spring JPA Json循环依赖的问题分析的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot JPA:在自联接关系中的 JSON 视图上递归