개요
- JPA Entity에 public or protected no-arg constructor가 필수인 이유
- JPA 엔티티 클래스의 기본 생성자와 리플렉션
JPA 명세
- 엔티티 클래스는 기본 생성자(매개변수가 없는 생성자)를 반드시 가져야 한다.
- 추가로 다른 생성자를 가지는 것은 상관 없다.
- 기본 생성자는 반드시 public 또는 protected로 선언되어야 한다.
원문
The entity class must have a no-arg constructor. The entity class may have other constructors as well. The no-arg constructor must be public or protected.
문제 제기
- 어차피 리플렉션으로 엔티티 인스턴스 생성하지 않나? 리플렉션 이용한다면 private이어도 상관 없지 않나?
JPA 엔티티 클래스의 기본 생성자와 리플렉션에 대한 정리
JPA 엔티티 클래스의 기본 생성자 요구 사항
- JPA 엔티티 클래스는 기본 생성자(매개변수가 없는 생성자)를 반드시 포함해야 한다.
- 기본 생성자는 public 또는 protected 접근 제어자를 가져야 한다.
- 기본 생성자가 없거나, private으로 선언되면 JPA가 해당 엔티티를 인스턴스화할 수 없다.
JPA의 리플렉션을 통한 객체 생성
- JPA는 리플렉션을 사용하여 엔티티 객체를 인스턴스화한다.
- 데이터베이스에서 엔티티를 조회하거나, 영속성 컨텍스트에 엔티티를 추가할 때 리플렉션을 사용해 객체를 생성한다.
- 이때 기본 생성자가 호출되며, 생성자 호출 후 필드에 데이터베이스 값을 설정한다.
리플렉션으로 private 생성자에도 접근할 수 있지만, JPA는 이를 사용하지 않음
- 리플렉션으로 private 생성자에 접근하려면 setAccessible(true) 메서드를 통해 접근 제어를 우회할 수 있다.
- 하지만 JPA는 자바 표준 접근 방식을 준수하려고 setAccessible(true)를 사용하지 않는다.
- private 생성자를 우회하는 것은 자바의 접근 제어 규칙을 위반하므로, JPA는 public 또는 protected 생성자만을 사용한다.
protected 생성자의 의미
- JPA는 최소 protected 기본 생성자를 요구한다.
- protected는 외부에서 엔티티를 직접 생성하지 못하게 하면서도, JPA가 리플렉션을 통해 객체를 생성할 수 있는 최소한의 접근 제어 수준이다.
- protected 생성자를 제공하면 상속받은 클래스나 JPA 프록시 객체에서 안전하게 접근 가능하다.
결론
- JPA 엔티티 클래스는 public 또는 protected 기본 생성자를 반드시 가져야 하며, 이는 JPA가 리플렉션을 사용해 객체를 인스턴스화할 때 필수적인 조건이다.
- 리플렉션을 통해 private 생성자에도 접근할 수 있지만, JPA는 Java의 표준 접근 규칙을 준수하기 위해 이를 사용하지 않는다.
- JPA 엔티티 클래스에서 protected 기본 생성자를 사용하는 이유는 안전한 캡슐화와 리플렉션을 통한 객체 생성, Java의 표준 접근 규칙 준수를 동시에 충족하기 위함이다.