[Spring] Lombok @Data @NoArgsConstructor

[verify$y]·2025년 5월 21일

Spring

목록 보기
2/16

Lombok의 @Data와 @NoArgsConstructor를 함께 쓰는 이유

1. @Data가 포함하는 기능

  • @Data는 Lombok이 제공하는 종합 애노테이션으로 다음 기능을 포함한다.
	@Getter, @Setter
	@EqualsAndHashCode
	@ToString
	@RequiredArgsConstructor

  • final 필드나 @NonNull 필드를 초기화하는 생성자를 자동으로 생성
  • 주의: @Data는 기본 생성자(@NoArgsConstructor) 를 생성하지 않는다.

2. JPA에서 기본 생성자가 필요한 이유

  • JPA는 프록시 객체를 만들기 위해 매개변수 없는 생성자를 필수로 요구한다.
    이 생성자는 protected 또는 private이어도 되며, JPA는 리플렉션을 통해 접근한다.

  • 하지만 클래스에 final 필드가 있으면, 기본 생성자 없이는 컴파일 에러가 발생하므로
    명시적으로 @NoArgsConstructor(force = true)를 사용해 강제로 기본값(null 등)으로 초기화해줘야 한다.

3. 왜 @Data와 @NoArgsConstructor를 같이 쓰는가?

  • @Data는 로직 상 필요한 getter/setter, toString 등을 자동 생성해주고

  • @NoArgsConstructor(force = true)는 JPA를 위한 기본 생성자를 제공해준다

  • 즉, 두 애노테이션은 역할이 다르기 때문에 상충되지 않고 함께 사용하는 것이 맞다.

4. 코드

## 예시1
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@Entity
public class Ingredient {
    @Id
    private final String id;
    private final String name;
    private final Type type;

    public static enum Type {
        WRAP, PROTEIN, ...
    }
}
  • 이렇게 하면 final 필드를 유지하면서도 JPA가 요구하는 기본 생성자를 갖춘 엔티티 클래스를 만들 수 있다.

## 예시2
import javax.persistence.*; 
import lombok.*; 

@Data
@RequiredArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@Entity
public class Ingredient {

    @Id
    private final String id;
    private final String name;
    private final Type type;

    public static enum Type {
        WRAP, PROTEIN, ...
    }
}

@Entity

  • 해당 클래스를 JPA가 관리하는 영속 엔티티로 선언하기 위해 반드시 붙여야 하는 애노테이션이다.
  • 이 애노테이션이 선언되어야 JPA가 해당 클래스를 테이블과 매핑하고 관리할 수 있다.

@Id

  • JPA에서 엔티티는 반드시 기본 키(primary key)를 가져야 한다.
  • @Id는 해당 필드가 테이블에서 고유하게 식별되는 기본 키임을 명시한다.
  • 여기서는 id 필드를 고유 식별자로 사용한다.

@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)

  • JPA는 내부적으로 프록시 객체 생성을 위해 기본 생성자(인자 없는 생성자) 를 필요로 한다.
  • 하지만 Ingredient 클래스는 final 필드를 포함하고 있어 일반적인 기본 생성자 생성이 불가능하다.
  • force = true를 지정하면 Lombok이 final 필드들을 기본값(null, 0, false 등)으로 강제로 초기화하면서 기본 생성자를 생성한다.
  • 외부에서 이 생성자를 호출하지 못하도록 access = AccessLevel.PRIVATE로 제한했다.

@RequiredArgsConstructor

  • final 또는 @NonNull이 붙은 필드를 매개변수로 받는 생성자를 생성한다.
  • id, name, type은 모두 final이므로 이 애노테이션에 의해 세 필드를 매개변수로 받는 생성자가 자동 생성된다.
  • 이 생성자는 객체 생성 시 필수 속성을 명확하게 전달하게 하며, 불변성을 유지하는 데 유용하다.

@Data

  • @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor를 포함한 복합 애노테이션이다.
  • 따라서 @Data만 사용해도 @RequiredArgsConstructor가 포함되지만, 여기서는 생성자 관련 제어를 명확하게 하기 위해 @RequiredArgsConstructor를 별도로 명시했다.
  • 또한 @Data는 생성자 자체를 제거하지는 않는다. @NoArgsConstructor와 함께 사용되더라도 생성자들이 각각 생성되며, Lombok은 중복되지 않게 처리한다.
  • 즉, @NoArgsConstructor로 기본 생성자를 따로 정의하고, @RequiredArgsConstructor로 필수 인자를 받는 생성자를 추가로 정의하는 방식은 충돌하지 않는다.
profile
welcome

0개의 댓글