JPA의 Entity는 반드시 파라미터가 없는 기본 생성자를 지녀야 한다.
그리고 그 기본 생성자는 public
, protected
이어야하고 private
으로 선언해서는 안된다.
Spring Data JPA 에서 Entity에 기본 생성자가 필요한 이유는 동적으로 객체 생성 시 Reflection API
를 활용하기 때문이다.
JPA는 DB 값을 객체 필드에 주입할 때 기본 생성자로 객체를 생성한 후 Reflection API
를 사용하여 값을 매핑한다.
때문에 기본 생성자가 없다면 Reflection
은 해당 객체를 생성 할 수 없기 때문에 JPA의 Entity에는 기본 생성자가 필요하다.
Reflection API
란?
자바에서는 JVM이 실행되면 작성된 자바 코드가 static 영역에 저장된다.
Reflection API는 이 정보를 활용하여 구체적인 클래스 타입을 알지 못해도 클래스 이름을 통해 static 영역에서 그 클래스의 정보(메서드, 타입, 변수 등등)에 접근할 수 있게 해준다.
다만 Reflection API가 생성자의 인자 정보는 가져올 수 없다.
때문에 기본 생성자가 있어야 객체를 생성할 수 있고 생성된 객체를 통해서 Reflection API는 필드 값 등을 넣어줄 수 있다.
JPA가 매핑한 Entity를 조회할 때 hibernate가 생성한 proxy 객체
를 사용하여 연관된 데이터를 실제 사용하는 시점에 조회할 수 있는데,
proxy 객체
는 직접 만든 객체 class를 상속하기 때문에 public 혹은 protected 기본 생성자가 필요하다. (private로 생성자를 만들게 되면 파생 클래스로부터의 상속 형태가 접근 불가가 되어버리기 때문에 제약이 생기게 된다)
proxy 객체
란?
JPA는 매핑한 Entity를 조회할 때 두 가지 전략을 사용한다.
조회 시점에 함께 가져오는 EAGER
와 매핑한 Entity를 사용할 때 조회하는 LAZY
가 있다.
그리고 이때 지연로딩(LAZY
)을 사용할 경우 임시로 hibernate가 생성한 proxy 객체
를 생성하고 가리키게 된다.
그럼 proxy 객체랑 생성자랑 무슨 상관일까?
proxy 객체는 직접 만든 class 를 상속하기 때문에 public, protected 기본 생성자를 필요로 하게 된다. 결국 만약 public, protected 생성자가 없다면 proxy 객체를 사용할 수 없게 되는 것이다.
기본 생성자를 private 으로 선언하였을 때 생길 수 있는 오류 (JpaSystemException) 이다.
오류 내역을 보면 친절하게 domain.User 의 Private 생성자는 런타임시 작동할 수 없다. 라고 나와있다.
Entity 는 동적으로 객체 생성 시 java의 Reflection API를 활용하기 때문에 기본 생성자가 필요하며,
Entity 를 조회하기 위해 생성되는 proxy 객체는 직접 만든 객체 class를 상속하기 때문에 public이나 protected 기본 생성자를 선언해야한다.
[참조]
https://hyeonic.tistory.com/191
https://tecoble.techcourse.co.kr/post/2020-07-16-reflection-api/
https://velog.io/@yebali/Spring-JPA에-기본-생성자가-필요한-이유
https://wbluke.tistory.com/6
이해하기 쉽게 정리해주셔서 감사합니다!🤩