본문 바로가기

Programing/OpenSource

[Lombok & Spring (Jackson)] @Getter(lazy=true)를 쓸 때 주의해야 할 점

효진님이 getter 에서 매번 객체를 만드는 것에 대해 이유를 물어봐서 한 번만 만들어지게 하기 위해서 아래와 같이 lazy 를 true로 했다.

import lombok.Getter;

public class TistoryIssueParams {

    @Getter(lazy = true)
    private final TistoryNumber tistoryNumber = TistoryNumber.of(tistoryNumberType, tistoryNumberValue);

이런 식으로 annotation을 달면 lombok은 AtomicReference 로 필드를 만들고 늦은 초기화를 하는 코드를 만든다.

늦은 초기화를 Double-checked locking idiom을 사용하는 것을 알 수 있다.

public class TistoryIssueParams {
    private final AtomicReference<Object> tistoryNumber = new AtomicReference();
    public TistoryNumber getTistoryNumber() {
        Object value = this.tistoryNumber.get();
        if (value == null) {
            synchronized(this.tistoryNumber) {
                value = this.tistoryNumber.get();
                if (value == null) {
                    TistoryNumber actualValue = TistoryNumber.of(this.tistoryNumberType, this.tistoryNumberValue);
                    value = actualValue == null ? this.tistoryNumber : actualValue;
                    this.tistoryNumber.set(value);
                }
            }
        }
        return (TistoryNumber)((TistoryNumber)(value == this.tistoryNumber ? null : value));
    }

 

문제는 Spring을 Controller의 파라미터로 받을 경우에 ClassCastException 예외가 발생할 수 있다.

이유는 Jackson이 AtomicReference<Object> 객체를 AtomicReference<TistoryNumber> 가 아닌 AtomicReference<LinkedHashMap> 로 인스턴스를 바꾸어 버리기 때문이다.

해결책

해결 방법은 간단하다.

Jackson에게 건들지마 하고 아래와 같이 @JsonIgnore 를 달아주면된다.

import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;

public class TistoryIssueParams {

    @JsonIgnore
    @Getter(lazy = true)
    private final TistoryNumber tistoryNumber = TistoryNumber.of(tistoryNumberType, tistoryNumberValue);