DevelopmentTools/jpa

[JPA] JPA가 기본 생성자가 필요한 이유 (feat. final)

수짱수짱 2023. 10. 12. 10:49

해당 게시글은 "프로그래머스 데브코스 4기"의 팀 내 프로젝트 기록용으로 TECH BLOG에 직접 작성한 글입니다.


1️⃣ JPA에서 기본 생성자를 필요로 하는 이유

JPA에서 Entity는 반드시 public 또는 protected인 기본 생성자를 가져야 한다

이것이 가능한 이유는 JPA가 자바에서 제공하는 리플렉션 API를 활용하여 동적으로 객체를 생성하기 때문이다

만약, 기본 생성자가 없거나 private인 경우 리플렉션 API는 객체를 생성할 수 없게된다.

 

리플렉션 API란 구체적인 클래스 타입을 몰라도 클래스 이름으로 메서드, 타입, 변수등 클래스의 모든 정보에 접근할 수 있도록 해주는 API이다.

리플렉션을 활용하여 런타임 시점에 동적으로 클래스 객체를 생성할 수 있는데 이때 객체를 생성하기 위해 기본 생성자를 통해 만드는 것이다.

 

그럼 매개 변수가 있는 생성자를 통해서는 JPA가 객체를 만들지 못하는가?에 대한 의문이 들 수 있다.

이때, 리플렉션도 모르는 정보가 있는데 그것은 바로 “생성자의 매개 변수 정보”이다

이런 이유 때문에 매개변수가 있는 생성자가 아닌 기본 생성자를 통해 객체를 생성하고 리플렉션을 통해 필드 값을 매핑해주는 방식을 사용하는 것이다.

 

🐼 참고로 필드 값을 매핑해줄 때 setter를 사용하지 않고 리플렉션을 통해 얻은 값으로 필드 값을 매핑해주는 것이다.

setter를 사용하지 않는다는 것을 유의해라.

2️⃣ 기본 생성자를 protected로 제한하는 이유

그렇다면 기본 생성자를 만들기만 하면 되는데 접근 제한자가 public이거나 protected이어야 하는 이유는 무엇일까?

바로 private은 상속이 불가능하기 때문이다.

+마찬가지로 default 제한자도 같은 패키지에 소속이 되어야만 하는 것이므로 상속이 불가능하다

 

🐼 그래서 보통은 public을 사용하지 않고 `protected`로 기본생성자 접근제한자를 제한해준다.

public을 사용한다면 어느 곳에서나 객체를 생성할 수 있는 길이 열리는 것이기 때문에..

언제 어디에서 객체가 생성될지 모르므로 public은 사용하지 않는 것이다.

 

그렇다면 상속이란 키워드가 왜 나오는 것일까? 바로 프록시(Proxy)객체 때문이다.

🐼 JPA와 프록시 객체의 상관관계는 어디서 나온 것?? → JPA의 Entity사이 연관관계가 있을 때 JOIN을 통해 조회한 결과를 효율적으로 가져오기 위해 시작

결과를 효율적으로 가져오기 위해 연관관계가 있는 Entity를 바로 가져오지 않고 실제 사용할 때만 가져오는 지연로딩(LAZY)를 택하면서 프록시 객체를 사용하게 되었다.

  • JPA에서 프록시란 실제 Entity 대신 데이터베이스 조회를 지연할 수 있는 “가짜 객체”를 의미한다.
  • 가짜 객체라고 해서 실제 Entity의 동작을 수행할 수 없는 것은 아니다.
    • 왜? 바로 실제 클래스를 상속받아 프록시 객체가 만들어지기 때문이다.

 

따라서 기본 생성자의 접근 제한자가 private으로 걸려있다면 JPA가 프록시 기술을 쓸 때(지연로딩) JPA hibernater가 객체를 만들 수 없을 것이다.

왜냐, 프록시 기술은 “상속”을 이용한 기술인데 private으로 인해 원본 Entity를 상속을 할 수 없게되기 때문이다.

3️⃣ JPA Entity 필드에 final 키워드를 붙일 수 없는 이유

만약, Entity 필드에 final 키워드를 붙이게 된다면 위 그림과 같은 에러 메시지가 뜬다.

🐼 Variable ‘필드명’ might not have been initalized → 변수 ‘필드명’이 초기화되지 않았을 수 있습니다.

이게 무슨말일까?

 

1️⃣에서 다룬 내용과 2️⃣에서 다룬 내용을 함께 보면 정답이 보인다!

1️⃣ - JPA가 기본 생성자를 통해 객체를 생성하고 필드 값을 리플렉션을 통해 매핑해주는 방식을 사용한다는 내용

2️⃣ - Entity간 연관관계가 있을 떄 지연로딩을 통해 값을 조회하는 경우 상속받은 프록시 객체를 사용한다는 내용

 

결론

자바의 final 키워드란 “단 한 번만 할당이 가능하며 변경이 불가능한 키워드”이다.

따라서, 1️⃣의 기본 생성자를 통해 객체를 생성한 이후 필드 값을 매핑 해줄 수 없게되는 것이다.

또한 2️⃣의 지연로딩을 위한 프록시 객체를 만들 때 상속이 필요한데 final 키워드가 걸린 필드는 상속에 제한이 걸리게 되므로(값을 수정할 수 없으므로) 프록시 객체를 만들 수 없게 되는 것이다.


Reference