* JDK14에서 preview로 등장하여 JDK16에서 정식 스펙으로 포함

불변(immutable) 객체를 쉽게 생성할 수 있도록 하는 유형의 클래스
	- 필드가 자동으로 final로 선언되어 불변 객체를 생성 (필드 캡슐화)
	- class가 final로 선언, final 클래스(상속불가)
	- 클래스의 필드 선언, 생성자, getter, equals, hashCode, toString이 모두 자동으로 생성 
	- 컴파일 타임에 컴파일러가 코드를 추가
	- getter를 사용할 때, getFieldName()이 아니라 fieldName()을 사용
	- Record 클래스가 제공해주는 메소드들은 재정의가 가능

1. 생성자는 모든 field를 포함
2. toString()도 모든 field를 포함
3. equals(), hashCode() 메서드는 invokedynamic based mechanism을 사용
4. getter는 field이름과 유사한 이름으로 생성 ex) id(), email()..
5. 기본적으로 java.lang.Record class를 상속받기 때문에 다른 class를 상속받을 수 없음
6. class가 final이기 때문에 다른 subclass를 생성할 수 없음
7. 모든 field는 불변이기 때문에 setter는 제공하지 않음
8. DTO(data transfer object)나 domain model class에 사용

Q. 레코드(record)를 JPA의 Entity 클래스로 사용할 수 없을까요?
레코드는 바이트코드로 본 것처럼 final 클래스(상속불가)이고, abstract로 선언할 수 없습니다.
따라서 레코드를 Entity 클래스에 사용할 수 없는데요, 그 이유는 JPA의 지연로딩에 있습니다.

지연 로딩 방식을 사용할 때, JPA는 엔티티 객체의 프록시 객체를 생성합니다. 
프록시 객체는 원본 객체를 상속하여 생성된 확장 클래스입니다. 
하지만 레코드는 상속이 불가능하므로 엔티티로 사용할 수 없습니다.

 

참고

 

예시 ResponseMessage<T>.java

package org.example.exception;

import lombok.Builder;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

@Getter
@Builder
@RequiredArgsConstructor
public class ResponseMessage<T> {
    private final HttpStatus status;
    private final String message;
    private final T data;

    public static ResponseEntity<ResponseMessage> error(CustomException e) {
        return ResponseEntity
                .status(e.getCustomErrorCode().getHttpStatus())
                .body(ResponseMessage.builder()
                        .status(e.getCustomErrorCode().getHttpStatus())
                        .message(e.getCustomErrorCode().getMessage())
                        .build());
    }

    public static <T> ResponseEntity<ResponseMessage> success(HttpStatus status, String message, T data) {
        return ResponseEntity
                .status(status)
                .body(ResponseMessage.builder()
                        .status(status)
                        .message(message)
                        .data(data)
                        .build());
    }
}

 

✏️ Class to Record 

package org.example.exception;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

public record ResponseMessage <T> (HttpStatus status, String message, T data) {

    public static ResponseEntity<ResponseMessage> error(CustomException e) {
        return ResponseEntity
                .status(e.getCustomErrorCode().getHttpStatus())
                .body(new ResponseMessage<>(
                        e.getCustomErrorCode().getHttpStatus(),
                        e.getCustomErrorCode().getMessage(),
                        null
                ));
    }

    public static <T> ResponseEntity<ResponseMessage> success(HttpStatus status, String message, T data) {
        return ResponseEntity
                .status(status)
                .body(new ResponseMessage<>(
                        status,
                        message,
                        data
                ));
    }
}

'Java' 카테고리의 다른 글

Try With Resource  (2) 2025.01.22
불변 객체(Immutable Object)  (0) 2025.01.18
제네릭(Generic)  (0) 2025.01.17