[KOTLIN] 드디어 생겼네요.. JPA 문제가.. 😂

RuiN·2023년 8월 13일
0
post-thumbnail

생각해보니까 문제가 있더라..

첫 입사한 회사에서 자바+스프링으로 개발을 시작했는데.. 물론 대한민국에서는 자바 스프링이 제일 대중적으로 쓰인다고 생각합니다.

하지만, 연차는 적지만서도 나중을 생각하면 다른 Skill도 필요하겠다 라는 생각이 강하게 들었다.
자바와 100% 호환된다는 Kotlin을 선택했다.

그래서 기존의 Java 사이드 프로젝트들을 기반으로 Kotlin으로 프로젝트를 진행해보고자 했다.

기본적인 Controller의 경우는 문제가 전혀 없었다. 그.러.나.

아무리 100% 호환이라고는 하지만, Java Spring에서 잘 적용되던 Entity형식의 코드들이 Kotlin에서는 유의할점으로 남아있다는 것이다.


문제라면 해결해야지!

물론 맞는말이다. 문제라면 해결하면 그만이다.
하지만, 프로젝트에 그대로 코드만 복붙해서 가느니, 한번쯤은 이론과 중요성에 대해서 알아보고자 합니다요.

어이 JPA 뭘 원하는데??

일단 뭐, 하이버네이트 사용가이드에서는 이렇다 저렇다 하는데, 여기서는 그 중에서 몇개만 다루어 보고자 합니다.

  • 엔티티 클래스는 매개변수가 없는 public또는 protected생성자를 가져야한다.
  • 지연로딩을 사용하려면 엔티티 클래스는 final이 아니여야 한다.

문제 해석 들어가자!

첫번째

일단 기본적으로 코틀린에서 Class 는 문법상 Property를 선언하면서 자동으로 생성되는 기본 생성자를 사용하는 경우가 대부분일것이다.
그리고 추가적인 생성자는 반드시 기본생성자를 상속해야하는 코틀린의 문법 특징으로 코틀린에서는 매개변수가 없는 생성자를 작성하는것이 굉장히 번거롭다.

이를 위해서 코틀린에서는 Gradle 또는 Maven에서 추가적인 plugIn을 지정하는 것으로 @Entity @Embeddable @MappedSuperClass 어노테이션이 붙은 모든 클래스에 자동으로 매개변수가 없는 생성자를 만들 수 있다.

참고로 필자는 Gradle(Kotlin) 이기에 << 이 기준을 따라서 작성할거에요~

plugins {
    ..
    kotlin("plugin.jpa") version "{Kotlin버전}"
    ..
}

위의 Gradle 설정에 추가하면, 코틀린을 자바코드로 디컴파일 했을때 매개변수가 없는 생성자가 추가가 되어있을 겁니다.
참고로 이 플러그인은 Spring JPA 를 추가했다면 추가할 필요는 없습니다.

두번째

코틀린의 모든 클래서는 기본적으로 final이죠?
엔티티 클래스가 final 클래스라고 해도 JPA를 사용하는 것 자체는 문제가 없지만!! 지연 로딩 (Lazy) 을 제대로 사용할 수가 없어요..

@OneToMany라면 별도의 걱정없이 지연로딩을 사용할 수 있지만!
@ManyToOne이라면 엔티티 클래스가 final 클래스라면 지연 로딩이 동작을 하지 않습니다.
따라서 엔티티 클래스들을 모두 OPEN 해줄 필요가 있습니다.

하지만! 엔티티 클래스마다 일일이 OPEN 키워드를 붙여주는것은 매우매우 귀찮은 일이죠?
그래서 이 또한 Gradle에서 설정을 해줄 수가 있습니다.

Gradle(Spring Boot 3.0.0 이상)

plugins {
    ..
    // Gradle(Groovy)
    id 'org.jetbrains.kotlin.plugin.allopen' version '{Kotlin버전}'	
    
    // Gradle(Kotlin)
    kotlin("plugin.allopen") version "{Kotlin버전}"	
    ..
}
 
allOpen {
    annotation("jakarta.persistence.Entity")
    annotation("jakarta.persistence.Embeddable")
    annotation("jakarta.persistence.MappedSuperclass")
}

Gradle(Spring Boot 3.0.0 미만)

plugins {
    ..
    // Gradle(Groovy)
    id 'org.jetbrains.kotlin.plugin.allopen' version '{Kotlin버전}'	
    
    // Gradle(Kotlin)
    kotlin("plugin.allopen") version "{Kotlin버전}"	
    ...
}
 
allOpen {
    annotation("javax.persistence.Entity")
    annotation("javax.persistence.Embeddable")
    annotation("javax.persistence.MappedSuperclass")
}

이렇게 설정해주면 되는데.. 주의할 점은~!
스프링부트 3.0.0부터는 org.springframework.boot:spring-boot-starter-data-jpa의 JPA 어노테이션들의 최상위 패키지가 javax에서 jakarta로 변경되었기 때문에 스프링부트 버전에 따라서 allOpen에 설정할 어노테이션의 패키지 명을 잘 작성해야 한다.


네 그렇습니다..

이렇게 해서 일단은 일단락이 된 기분인데.. 아마 개인프로젝트를 진행하면서 계속 들락날락 할것같아요~..

유익했다면 댓글 한번만 달아주시고, 혹시 틀린정보가 있다면 말씀해주시면 수정해서 다시 포스팅하겠습니다 😊

profile
어디까지 올라갈지 궁금한 하루

0개의 댓글