JPA Jackson Stack OverFlow 이슈

Daeyoung Nam·2021년 10월 12일
1

프로젝트

목록 보기
10/16

issue?

Jackson이 양뱡향 연관관계가 얽혀있는 클래스를 json으로 변환할 때 StackOverFlow가 발생했다.

예제 소스코드

부모 Entity

@Entity
class User (
    username: String,
    email: String,
    password: String,
    profileImage: String,
    authority: Authority,
    registrationType: RegistrationType
) : BaseTimeEntity() {

    @Id
    @Column(name = "id")
    var email: String = email

    var username: String = username
    var password: String = password
    var profileImage: String = profileImage
    var authority: Authority = authority
    var registrationType: RegistrationType = registrationType

    @OneToMany(mappedBy = "user", cascade = [CascadeType.ALL], orphanRemoval = true)
    var userSavedMountains: MutableSet<UserMountain> = mutableSetOf()
        set(value) {
            if(field == null) {
                field = value
            }
            else {
                field.clear()
                field.addAll(value)
            }
        }
}
@Entity
class UserMountain(
    user: User,
    mountainCode: String
): BaseTimeEntity() {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = 0

    @ManyToOne(fetch = FetchType.EAGER)
    @get:JoinColumn(name = "user_id")
    var user = user

    var mountainCode = mountainCode

    override fun equals(other: Any?): Boolean {
        return this.id == (other as UserMountain).id
    }

    override fun hashCode(): Int {
        return this.id.hashCode()
    }

}

여기서 UserMountain을 json으로 반환해주는 API를 만들고있었는데 StackOverFlow가 떴었다.

이유는 파싱하는 과정에서 UserMountain에 있는 User 클래스에도 접근하여 파싱하고 또 User에 있는 UserMountain set collection또 파싱하면서 순환 참조가 일어났었다

UserMountain -> User -> UserMountain -> User ...

해결

그래서 자식 엔티티에 @JsonIgnore 어노테이션을 붙여서 해결했다.
다른 방법으로는 얻어온 엔티티를 DTO로 바꿔서 반환하는 방법도 있겠다.

@Entity
class UserMountain(
    user: User,
    mountainCode: String
): BaseTimeEntity() {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = 0

    @JsonIgnore // Jackson이 Json으로 변환하는 과정에서 연관관계 때문에 stackoverflow가 발생하는 이슈가 있었음
    @ManyToOne(fetch = FetchType.EAGER)
    @get:JoinColumn(name = "user_id")
    var user = user

    var mountainCode = mountainCode

    override fun equals(other: Any?): Boolean {
        return this.id == (other as UserMountain).id
    }

    override fun hashCode(): Int {
        return this.id.hashCode()
    }

}

두번째 방법이 더 좋은 방법인듯 하다.

이러한 이슈때문에 Entity 자체를 직접 반환하는것 보단 DTO에 담아서 리턴을 하는 방향으로 하는게 더 좋은 코딩인것같다.

profile
내가 짠 코드가 제일 깔끔해야하고 내가 만든 서버는 제일 탄탄해야한다 .. 😎

0개의 댓글