[Lombok] @NoargsConstructor(AccessLevel.PROTECTED), @Builder

Coodori·2023년 4월 3일
0

CherishU

목록 보기
19/29

문제 발생

@RequestBody로 받아오는 Dto에서 바인딩되지 않는 오류가 발생하였다.

문제 파악

1번 사용이유

현재 Dto는 모두 @Data처리가 되어있다.

하지만 왜 우리의 Dto에 바인딩이 되지 않을까?

일단 내가 알고있는 지식으로 저번 편에 이어

  • JAVA객체가 JSON으로 변환될때는 JACKSON 라이브러리가 사용되는 것으로 알고 있다.
  • 그렇다면 JSON을 어떻게 JAVA 객체에 바인딩이 가능한 걸까?

해당 블로그를 참고하여 궁금증을 풀었다.(하나하나 들어가서 직접 같이 찾아보았다.)
왜 기본 생성자가 필요한가
굉장히 코드 분석이 잘 되어있어서 원리에 대해 알아갔다.

property명은 setter, getter 혹은 public field를 보고 찾는다.
값 주입은 java.lang.reflect 패키지를 사용해 직접 주입시킨다.

그리고 해당 @NoargsConstructor

이 부분에서 사용이 된다.

기본 생성자가 없다면 이 부분을 통과하지못하고


에러를 출력하게 되는 것이다.

결론

그래서 우리는 @RequestBody 에 매핑될 클래스에 기본 생성자를 꼭 적어주어야한다!

2-1번 (AccessLevel.PROTECTED)

해당 옵션으로 설정하였을 경우
기본 생성자의 접근 제어를 PROTECTED로 설정해놓게 되면 무분별한 객체 생성에 대해 한번 더 체크할 수 있는 수단이 되기 때문입니다

추가로 이펙티브 자바에는 이런 문구가 있습니다.

Effective Java - Item 15의 내용에서 접근 제한자는 가능한 좁히는 것을 원칙
가능한 한 다른 곳에서 접근 불가능하도록 만들어라. 클라이언트에게 제공하는 API만 public 또는 protected로 하라.

그래서 무분별한 생성자 생성을 방지하기 위해 PROTECTED 레벨로 설정합니다.

2-2번 @Builder와 @NoargsConstructor

@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    private Long id;
    private int age;
    private String email;
}

언뜻보면 이렇게 활용이 가능할듯하다.
하지만 해당 User는 Error를 동반한다.

왜냐하면 @Builder 같은 경우 생성자가 없으면 직접 모든 파라미터의 생성자를 만들어주지만 만약 생성자가 존재하면 그 생성자를 이용한다.
그래서 아무것도 없는 생성자에 빌더가 적용이 되어서 사용이 불가하다.

 public User build() {
            /// 일치하는 생성자가 없다.
            return new User(this.id, this.age, this.email); 
        }

그렇다면 해결 방법은?

총 2가지가 있다.

  1. 위에서 말한 방법대로 생성자를 모두 포함하게 명시해주는 것이다. 그렇다면 그 생성자를 @Builder가 사용할 것이다.
@Builder
@AllargsConstructor
public class User {
    private Long id;
    private int age;
    private String email;
}
  1. 혹은 생성자를 직접 명시해주는 것이다.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    private String name;
    private Long age;
    private String email;

    @Builder
    public User(String name, Long age, String email) {
        this.id = name;
        this.age = age;
        this.email = email;
    }
}

결론

개발자를 편리하게 해주는 롬복 잘 알고 사용하면 좋을 듯하다.

또한 두가지를 합치면
결국 @ResquestBody는 기본 생성자와 빌더를 사용하게 될 경우 1번 경우를 사용하게 된다.
그렇다면 코드는

@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllargsConstructor
public class UserDto {
    private Long id;
    private int age;
    private String email;
}

가 될 것이다.

추가로 해당 문제를 해결하면서
리플렉션과 기본생성자
문서도 함께 참고하였다.

REFERENCE

https://blogshine.tistory.com/445
https://cobbybb.tistory.com/14
https://jaehoney.tistory.com/287

profile
https://coodori.notion.site/0b6587977c104158be520995523b7640

0개의 댓글