@NoArgsConstructor

  • Rest Controller에서 @NoArgsConstructor 명시 이유

    1. 객체 역직렬화(Deserialization) 지원

    • Jackson (Spring Boot의 기본 JSON 처리 라이브러리)은 JSON → Java 객체로 변환할 때 기본 생성자가 필요합니다.

    • 예: 클라이언트가 전송한 JSON 데이터를 @RequestBody로 바인딩할 때

    @PostMapping("/users")
    public ResponseEntity<Void> createUser(@RequestBody UserDto dto) {
        // JSON → UserDto 변환
    }
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserDto {
        private String name;
        private int age;
    }

    여기서 @NoArgsConstructor가 없다면 Jackson이 UserDto를 만들 수 없어 400 오류 또는 예외가 발생합니다.

2. JPA 엔티티에서 프록시 생성 필요

  • JPA는 엔티티를 프록시로 감쌀 때 기본 생성자가 반드시 있어야 동작합니다.

    • JPA를 사용하는 클래스에 @Entity를 붙였다면 @NoArgsConstructor(access = AccessLevel.PROTECTED)를 보통 함께 사용합니다.

✅ 1. access = AccessLevel.PROTECTED가 필요한 이유

🔹 기본 생성자는 JPA 내부에서 꼭 필요

  • JPA(Hibernate)는 엔티티 객체를 리플렉션 기반으로 생성합니다.

  • 이 과정에서 반드시 기본 생성자가 있어야 하고, public 또는 protected 접근자여야 합니다.

private이면 Hibernate가 접근하지 못해서 에러 발생 public이면 누구나 생성할 수 있으므로 객체 무결성이 깨질 수 있음

✅ 그래서 protected로 막는 이유:

  • 외부에서 직접 객체 생성을 막고

  • JPA 내부에서는 리플렉션으로 생성 가능하게 → 객체 생성의 의도를 명확히 통제할 수 있음


✅ 2. 프록시로 감싼다는 건 무슨 의미?

🔹 JPA는 성능 최적화를 위해 지연 로딩(Lazy Loading) 을 사용

  • 예를 들어 UserTeam을 참조할 때, 실제 DB 조회는 getTeam() 호출 시점에만 일어납니다.

  • 이걸 위해 JPA는 **실제 객체 대신 프록시 객체(가짜 클래스)**를 먼저 생성합니다.

user.getTeam() 호출 전까지는 team은 실제 Team이 아니라 프록시 객체 → 이 프록시 객체를 만들기 위해 리플렉션으로 기본 생성자 호출이 필요함


🧠 정리

항목
이유

@NoArgsConstructor

JPA, Jackson 등 프레임워크에서 리플렉션으로 객체 생성 시 필요

access = PROTECTED

외부에서 무분별한 객체 생성을 막고 JPA 내부에만 허용

프록시 사용 목적

지연 로딩(Lazy Loading)을 위해 실제 대신 프록시 객체 생성

🎯 예시: User 엔티티


✅ 의도한 객체 생성 방식 (좋은 경우)

서비스나 도메인 내부에서 명시적으로 생성자 사용:

이렇게 하면 생성자 내부에 불변성 체크, 비즈니스 로직 등을 넣을 수 있어서 객체 일관성을 보장할 수 있음.


❌ 외부에서 기본 생성자로 객체를 생성한 경우 (문제 되는 예)

문제점:

  • 객체 생성 시 유효성 검사가 빠짐 (예: username이 null일 수도 있음)

  • 생성자 로직 우회

  • 도메인 무결성, 일관성이 깨질 수 있음


💡 그래서 @NoArgsConstructor(access = AccessLevel.PROTECTED)로 막는 이유

→ 외부에서는 new로 직접 만들 수 없음 → new User("gptchat")처럼 명시적인 생성 방식만 허용됨 → 객체 생성에 의도를 부여하고, 안정성을 확보


🔒 결론

접근 제어자
생성 가능 위치
의미

public

어디서나 가능

실수로 잘못 생성될 수 있음

protected

같은 패키지 또는 상속 관계만

외부 생성 차단하면서 JPA는 허용

private

클래스 내부만 가능

JPA에서 리플렉션 접근도 불가능 (❌ 사용 금지)

따라서 @NoArgsConstructor(access = AccessLevel.PROTECTED)외부 직접 생성 방지 + JPA 리플렉션 허용을 동시에 만족하는 안전한 기본 생성자 설계 방식입니다.

Last updated