작지만 꾸준한 반복

Lombok is- 필드 직렬화 버그 트러블슈팅 본문

트러블슈팅

Lombok is- 필드 직렬화 버그 트러블슈팅

iamjooon2 2024. 2. 9. 00:15

요즘 진행중인 프로젝트에서는 API 응답이 성공했는지, 혹은 실패했는지를 포함한 기본 응답 포맷을 사용한다

 

ResponseBodyAdvice 인터페이스를 구현하여

컨트롤러의 ResponseEntity가 생성된 후, HttpMessageConverter를 거쳐 직렬화 되기 전에 공통된 응답을 감싸 보내는 형식이다

 

게시글 적으면서 알게 된건데, 이런걸 봉투 패턴(Envelope Pattern) 이라 하더라

 

아무튼 각설하고, 이 기본 응답엔 isSuccess 필드가 하나 있어서

성공하면 isSuccess : true, 실패하면 isSuccess : false를 기본으로 반환하려 한다

 

감싸 보내는 코드는 다음과 같다

@Getter
public class BaseResponse<T> {

    private final boolean isSuccess;
    private final T result;
    
    public BaseResponse(T result) {
        this.isSuccess = true;
        this.result = result;
    }
    
}

@Getter
public class ErrorResponse<T> {

    private final boolean isSuccess;
    private final String code;
    private final String message;
    private final T result;
    
    public BaseResponse(ExceptionType exceptionType, T result) {
        this.isSuccess = true;
        this.code = exceptionType.getCode();
        this.message = exceptionType.getMessage();
        this.result = result;
    }
    
}

 

 

별 특이한 점은 없어 보이지만, 요걸 테스트하기위해 스웨거로 API 콜 때려보면 아주 신기한 일이 발생한다

 

 

prefix인 is-가 없어져서 success가 나온다

 

처음엔, @JsonProperty를 사용해서 임의의 값을 설정해줬다

그랬더니 isSuccess는 생겼지만, success도 그대로 있었다

 

빌드 후 인텔리제이의 classes 파일을 확인했다

 

result 필드의 게터는 getResult()로 잘 만들어졌는데, isSuccess는 isSuccess()로 만들어졌다

 

근데 응답 보내면 success도 오고, isSuccess도 오잖아....

 

수상하다...

 

@JsonProperty를 지우고 다시 빌드를 돌려봤다

 

isSuccess()가 그대로 있다

 

이친구... @JsonProperty 때문에 나온 친구가 아니었다?

 

생각해보니 @JsonProperty는 json에 매핑해주는 놈이니, 빌드된 파일과는 상관없다..ㅋㅋㅋㅋ

 

결국 롬복의 @Getter 요녀석이 getIsSuccess()로 안만들고, isSuccess()로 만들었다는 얘기다 

 

클린코드에서는 boolean 데이터 타입을 반환하는 함수의 경우, is-, can-, has-의 접두사를 붙이라고 말한다

 

관련이 있으려나 ?

 

isSuccess의 데이터 타입을 int로 바꾸고 다시 빌드를 해봤다

 

 

 

getIsSuccess()로 생성된다

 

다시 데이터타입을 boolean으로 바꿔주고, is- 접두사를 빼보고 빌드를 돌려봤다.

 

boolean이라 그런가 is- 가 붙어서 나온다....

 

결국.. 롬복이 boolean 필드의 경우 게터를 is-로 컴파일 한다는 얘기였다

 

그럼 롬복을 안쓰고 그냥 Getter를 만들어주면 될려나?

 

롬복 안쓰고 직접 get-으로 시작하는 게터들을 만들어주고 API 콜 때려봤다

 

 

잘.. 나온다....

 

문제는 해결했는데, 소소한 고민이 생겼다

 

BaseResponse는 필드가 두 개밖에 없어서 그렇다 쳐도, ExceptionResponse는 필드가 여러개인데 이거 다 게터 만들어줘야할까?

 

찾아보니 @Getter(AccessLevel.NONE)을 통해 특정 필드의 접근을 막을 수 있다고 한다

 

트러블슈팅 다 했으니.. 빠르게 글을 마무리 지어본다

 

해결 & 결론

롬복은 boolean 필드는 getIs-가 아닌 is- 식으로 메서드를 만든다

isSuccess는 롬복을 사용하지 않고, 직접 getter를 만들어줘서 해결했다

 

최종 코드는 아래와 같다

public class BaseResponse<T> {

    private final boolean isSuccess;
    private final T result;
    
    public BaseResponse(T result) {
        this.isSuccess = true;
        this.result = result;
    }
    
    public boolean getIsSuccess() {
        return isSuceess;
    }
    
    public T getResult() {
        return result;
    }
    
}

@Getter
public class ErrorResponse<T> {

    @Getter(AccessLevel.NONE)
    private final boolean isSuccess;
    private final String code;
    private final String message;
    private final T result;
    
    public BaseResponse(ExceptionType exceptionType, T result) {
        this.isSuccess = false;
        this.code = exceptionType.getCode();
        this.message = exceptionType.getMessage();
        this.result = result;
    }
    
    public boolean getIsSuccess() {
        return isSuccess;   
    }
    
}​