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