[Kotlin+Spring] Hibernate에 data class 사용하기

조오닭·2022년 4월 11일
0

코틀린+스프링부트+JPA를 처음 사용하다보면 정말 뜬금없는 곳에서 에러가 많이 발생한다.
대표적인 예로는 no-arg constructor인데, JPA의 구현체인 Hibernate가 Reflection을 사용하기 때문이다.

Reflection은 구체적인 클래스의 타입(형)을 알지 않아도 접근할 수 있도록 해주는 기능을 한다.
다만 생성자의 인자 정보를 가져올 수 없어 기본 생성자를 필수로 두어야한다.
따라서 총제적으로 정리하자면, Spring+JPA(Mybatis는 잘 모르겠음)를 사용할 때 객체 생성 시에 Hibernate가 Reflection을 사용하고, Reflection은 기본 생성자를 요구하는 것이다.
(Reflection의 더 자세한 설명은 이 글을 통해 확인할 수 있다.)

또 다른 오류로는 lazy loading 즉 지연로딩이 불가능하다.
Lazy loading은 프록시를 사용하고 프록시는 상속을 사용하기 때문에, data class로 이루어진 Entity에서 제대로 작동하지 않는 것이다.

한편 코틀린의 data class는 기존 자바 클래스의 코드를 단순화 시켜준다는 것에 장점이 있다.
지긋지긋했던(^^) Getter, Setter, Constructor(생성자)를 생략할 수 있는데, 코틀린을 이용하는 개발자라면 꿀이 아닐 수 없는 것이다.
다만 data class를 사용한다면 생략된 constructor를 Hibernate가 인식하지 못하고, 기본적으로 final으로 선언되어 상속이 불가능하다. 즉 기본 생성자를 억지로라도 생성하고 지연 로딩을 포기해야 한다.


해결 방법

build.gradle 파일에 다음 플러그인을 적용하면 된다.

plugins{
	kotlin("plugin.jpa") version "1.6.10" //version에 kotlin version을 기입
    id("org.jetbrains.plugin.allopen") version "1.6.10"
}

1. plugin.jpa

plugin.jpa는 다음 annotation에 자동으로 기본 constructor를 생성하게 해주는 플러그인이다.

@Entity, @Embeddable, @MappedSuperclass

만약 이 세 annotation 외에 다른 기존의 annotation을 추가하고 싶다면 build.gradle 하단에 다음 코드를 추가하면 된다.

noArg{
	//기본형 : annotation("fqName") //fqName에 annotation 출처(?)를 기입
}

2. allopen : open으로 선언

allopen은 다음 annotation에 사용된 class에 open으로 바꿔주는 플러그인이다.
(구글링해보니 사실 open으로 완전 탈바꿈하는 건 아니라고 함. open처럼 행동하는~인 것 같다.)

@Component
@Async
@Transactional
@Cacheable
@SpringBootTest
(+@Component를 상속받는 @Configuration, @Controller, @RestController, @Service, @Repository)

만약 plugin.jpa와 같이 기존의 annotation을 추가하고 싶다면 build.gradle 하단에 다음 코드를 추가하면 된다.

allOpen{
	//기본형 : annotation("fqName") //fqName에 annotation 출처(?)를 기입
    annatation("javax.persistence.Entity")
}

필자는 Entity annotation에 data class를 사용했으므로 Entity를 추가하였다.

더 자세한 설명은 All Open 공식 문서NoArg 공식 문서를 확인하자!

끝!

profile
백엔드 응애

0개의 댓글