접근제한자와 JPA

김성호·2023년 1월 18일
0

Java

목록 보기
2/6

Q.기본생성자가 private이면 JPA는 왜 proxy객체를 못 만들까?

@NoargsConstructor(AccessLevel.Private)

이렇게 기본생성자를 private으로 했더니 다음과 같은 예외가 발생했다.

  1. NoSuchMethodException
  2. HibernateException

대체 왜 이런 예외가 발생했을까?

조금 자세하게 알아보자.

Hibernate는 proxy 객체를 어떻게 생성할까?

  • 자바는 컴파일이 끝나면 소스코드들이 byte code로 이루어진 class파일로 변형된다.
  • Hibernate는 이 byte code에 접근해서 proxy 객체를 만들기 위해 byte code manipulation library를 사용한다.
    이 라이브러리는 Hibernate의 버전마다 다른 것을 사용한다고 한다.
  • byte code manipulation library는 이름에서 느껴지는 것 처럼 컴파일되서 나온 byte code에 접근하고 그것들을 조작할 수 있다.

문제가 발생하는 과정은 다음과 같다.

  1. Hibernate가 proxy객체를 만들기 위해 byte code manipulation library를 이용해 byte code에 접근한다.
  2. 그러나 기본생성자가 private이기 때문에 그 것을 제외하고 나머지 것들을 가져온다.
  • 왜냐하면 private은 클래스 외부에서 접근을 막는 접근제한자이기 때문이다.
  • java.lang.class.getConstructor()를 통해 변환된 code에서 기본생성자를 가져올려고 했는데 기본생성자가 보이지 않는다.
  • 여기서 하나의 포인트는 Hibernate가 Java의 Reflection API를 사용해서 가져온다는게 아니다.
  1. 그 후 proxy객체를 만들려고 하니... 어? 기본생성자가 없다.

이 순간 NoSuchMethodException이 발생한다.

개인적으로 신기하다고 생각한건, byte code class에 접근은 한다는 것이다.
그러나 정확하게 기본생성자에만 접근을 못한다는 것이었다.

따라서 기본생성자가 없어서 Hiberante가 proxy객체를 못 만들기 때문에
HibernateException이 발생한다.

org.hibernate.HibernateException: HHH000143: Bytecode enhancement failed because no public, protected or package-private default constructor was found for entity: com.encore.petandbe.model.accommodation.accommodation.Accommodation. Private constructors don't work with runtime proxies!

자, 그럼 이 문제를 어떻게 해결해야 할까? 그리고 왜 그렇게 해결해야 할까?

byte code manipulation library를 통해 접근할 수 있게 기본생성자의 접근제한자를 private이 아닌 public, protected, package-private(default)로 하면 된다.

여기서 또 하나의 포인트가 있다.

그 중에서도 protected가 보안상의 이유 떄문에 가장 좋다고 한다.
언뜻 보기엔 protected와 default가 비슷해 보이지만 protected가 좀더 명확하기 때문에 유지보수 측면에서 유리하기 때문이다.

profile
개발공부하는사람

0개의 댓글