Summary
- Entity의 OneToMany, ManyToOne 관계에서 출력 할 경우 무한 양방향 순환 참조가 일어난다.
- Entity를 그대로 출력하지 말고, Entity → Model(dto)로 변환시킨 후 출력하면 해결된다.
- @JsonIgnore, @JsonIgnoreProperties, @JsonIgnoreType으로도 해결할 수 있다.
증상
- User, Authority Entity
@Entity
public class USERTest {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column()
@NotNull
private String username;
@Column()
@NotNull
private String password;
@JsonIgnore()
@OneToMany(mappedBy = "user", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<AUTHORITYTEST> authorities = new ArrayList<>();
}
public class AUTHORITYTEST {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
//@ColumnDefault("ROLE_USER")
@Column
private String authority;
@Column
private String userName;
@ManyToOne
@JoinColumn(name= "user_id")
@JsonIgnore()
private USERTest user;
}
- Test
@Test
void jpaTest2() {
USERTest user = new USERTest();
user.setUsername("test0");
List<AUTHORITYTEST> authorityList = authorityTestRepository.findAuthorityByUserName(user.getUsername());
for (AUTHORITYTEST authoritytest : authorityList) {
log.info("{}", authoritytest);
}
}
- 결과
java.lang.StackOverflowError
at tom.study.domain.test.AUTHORITYTEST.toString(AUTHORITYTEST.java:12)
at java.base/java.lang.String.valueOf(String.java:4220)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)
at org.hibernate.collection.spi.PersistentBag.toString(PersistentBag.java:590)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at tom.study.domain.test.USERTest.toString(USERTest.java:14)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at tom.study.domain.test.AUTHORITYTEST.toString(AUTHORITYTEST.java:12)
at java.base/java.lang.String.valueOf(String.java:4220)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)
at org.hibernate.collection.spi.PersistentBag.toString(PersistentBag.java:590)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at tom.study.domain.test.USERTest.toString(USERTest.java:14)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at tom.study.domain.test.AUTHORITYTEST.toString(AUTHORITYTEST.java:12)
at java.base/java.lang.String.valueOf(String.java:4220)
at java.base/java.lang.StringBuilder.append(StringBuilder.java:173)
at java.base/java.util.AbstractCollection.toString(AbstractCollection.java:457)
...
원인
- USER와 AUTHORITY는 서로를 자신의 필드로 가지고 있다. 이 때 Jpa Repo로 entity를 가져와 출력시키면 AUTHORITY→USER→AUTHORITY→USER→ … 형태로 무한루프에 빠지게 된다.
해결법
- Entity를 dto로 변환 후 직렬화 한다.
- @JsonIgnore, @JsonIgnoreProperties, @JsonIgnoreType 어노테이션을 사용한다.
- @JsonIgnore- 어노테이션들은 해당 필드or클래스의 Json 직렬화를 무시한다.
- @JsonIgnore : 클래스의 속성에 명시
- @JsonIgnoreProperties : 클래스에 명시, @JsonProperty에 명시된 필드를 무시한다.
- @JsonIgnoreType : 클래스에 명시, 해당 클래스는 Json 직렬화 불가
Share article