# @NoArgsConstructor

* Rest Controller에서 @NoArgsConstructor 명시 이유

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

  * Jackson (Spring Boot의 기본 JSON 처리 라이브러리)은 JSON → Java 객체로 변환할 때 기본 생성자가 필요합니다.
  * 예: 클라이언트가 전송한 JSON 데이터를 `@RequestBody`로 바인딩할 때

  ```java
  @PostMapping("/users")
  public ResponseEntity<Void> createUser(@RequestBody UserDto dto) {
      // JSON → UserDto 변환
  }
  ```

  ```java
  @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)`를 보통 함께 사용합니다.

```java
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    @Id
    private Long id;
    private String name;
}
```

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

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

* JPA(Hibernate)는 엔티티 객체를 **리플렉션 기반**으로 생성합니다.
* 이 과정에서 반드시 **기본 생성자**가 있어야 하고, **`public` 또는 `protected` 접근자**여야 합니다.

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

#### ✅ 그래서 `protected`로 막는 이유:

* **외부에서 직접 객체 생성을 막고**
* **JPA 내부에서는 리플렉션으로 생성 가능하게**\
  → 객체 생성의 **의도를 명확히 통제**할 수 있음

***

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

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

* 예를 들어 `User` → `Team`을 참조할 때, 실제 DB 조회는 `getTeam()` 호출 시점에만 일어납니다.
* 이걸 위해 JPA는 \*\*실제 객체 대신 프록시 객체(가짜 클래스)\*\*를 먼저 생성합니다.

```java
@Entity
public class User {
    @ManyToOne(fetch = FetchType.LAZY)
    private Team team;
}
```

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

***

### 🧠 정리

| 항목                   | 이유                                       |
| -------------------- | ---------------------------------------- |
| `@NoArgsConstructor` | JPA, Jackson 등 프레임워크에서 리플렉션으로 객체 생성 시 필요 |
| `access = PROTECTED` | 외부에서 무분별한 객체 생성을 막고 JPA 내부에만 허용          |
| 프록시 사용 목적            | 지연 로딩(Lazy Loading)을 위해 실제 대신 프록시 객체 생성  |

### 🎯 예시: `User` 엔티티

```java
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class User {
    @Id @GeneratedValue
    private Long id;

    private String username;

    // 명시적인 생성자
    public User(String username) {
        this.username = username;
    }
}
```

***

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

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

```java
// 서비스 코드
User user = new User("gptchat");
userRepository.save(user);
```

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

***

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

```java
// 컨트롤러나 테스트 등 외부 코드에서
User user = new User();  // 기본 생성자 사용
user.setUsername("gptchat");  // 직접 필드 수정

userRepository.save(user);
```

#### 문제점:

* 객체 생성 시 유효성 검사가 빠짐 (예: username이 null일 수도 있음)
* 생성자 로직 우회
* 도메인 무결성, 일관성이 깨질 수 있음

***

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

```java
java코드 복사User user = new User(); // 컴파일 에러 or 접근 불가
```

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

***

### 🔒 결론

| 접근 제어자      | 생성 가능 위치         | 의미                           |
| ----------- | ---------------- | ---------------------------- |
| `public`    | 어디서나 가능          | 실수로 잘못 생성될 수 있음              |
| `protected` | 같은 패키지 또는 상속 관계만 | 외부 생성 차단하면서 JPA는 허용          |
| `private`   | 클래스 내부만 가능       | JPA에서 리플렉션 접근도 불가능 (❌ 사용 금지) |

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