final class는 JPA Entity Class가 될 수 없다. 왜 그럴까?
JPA는 DB에서 데이터를 조회한 후 엔티티를 생성할 때 지연 로딩이라는 방식을 사용한다.
지연 로딩이란?
해당 엔티티(테이블)와 관계(join)를 맺고 있는 엔티티(테이블)들에 대한 정보는 그 즉시 로딩되지 않고 getter 메소드가 호출되는 등 실제 사용될 때 로딩된다. 이러한 방식을 지연 로딩이라 한다.
지연 로딩 방식을 이용해 데이터를 조회하기 위해서, JPA는 프록시 객체라는 것을 생성한다. 프록시 객체는 간단히 말해서 엔티티를 상속해서 확장한 클래스이다. 하지만 final class는 상속될 수 없기 때문에 JPA는 final class를 확장해서 프록시 객체로 사용할 수가 없다. 따라서 JPA Entity로 사용하고 싶은 클래스는 final class가 아니어야 한다.
final field가 포함된 class 역시 JPA의 Entity가 될 수 없다. 왜?
Entity class는 JPA에 의해 프록시 객체로 확장된다. 그리고 JPA는 이 프록시 객체를 생성할 때 Reflection API를 이용한다. reflection으로 객체를 생성하기 위해서는 그 객체가 기본 생성자를 가지고 있어야 한다. 이렇게 생성된 프록시 객체의 필드들을 초기화 하기 위해 setter를 사용한다. 하지만 final 필드는 setter를 이용해서 초기화할 수 없다. final 필드는 클래스 로딩 시점에 초기화 되거나 생성자를 이용해서만 초기화될 수 있다. 따라서 JPA의 Entity로 사용할 class는 final 필드를 가질 수 없다.