@NoargsConstructor(AccessLevel.Private)
이렇게 기본생성자를 private으로 했더니 다음과 같은 예외가 발생했다.
- NoSuchMethodException
- HibernateException
조금 자세하게 알아보자.
- Hibernate가 proxy객체를 만들기 위해 byte code manipulation library를 이용해 byte code에 접근한다.
- 그러나 기본생성자가 private이기 때문에 그 것을 제외하고 나머지 것들을 가져온다.
- 왜냐하면 private은 클래스 외부에서 접근을 막는 접근제한자이기 때문이다.
- java.lang.class.getConstructor()를 통해 변환된 code에서 기본생성자를 가져올려고 했는데 기본생성자가 보이지 않는다.
- 여기서 하나의 포인트는 Hibernate가 Java의 Reflection API를 사용해서 가져온다는게 아니다.
- 그 후 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가 좀더 명확하기 때문에 유지보수 측면에서 유리하기 때문이다.