Kotlin과 JPA
in Programming Language on Kotlin
Kotlin과 JPA
스프링 JPA의 기본 메소드인 findById
의 경우 반환 값은 Optional<T>
이다.
나는 여태 스프링에서 kotlin-jpa
plugin을 추가하면 Kotlin의 Nullable 타입으로 받을 수 있는 줄 알았는데 아니었다. (멍청이)
val post: Optional<Post> = postRepository.findById(1)
아래는 코틀린에서 JPA Repository의 findById 메소드를 사용하여 DB에서 ORM 기술을 사용해 객체를 가져온 코드이다.
보면 알겠지만, 자바의 Optional로 받아온다.
이를 해결하기 위한 여러 방법이 있지만 그 중에 가장 합리적인 방법으로는 두 가지 방법이 있다.
1. 확장 함수를 사용해 Nullable 객체를 받을 수 있게 한다.
val post = Post(
null,
"테스트용"
)
val savePost = postRepository.save(post)
val findPost = postRepository.findByIdOrNull(savePost.id) ?: return
println(findPost::class.simpleName)
findByIdOrNull는 Springboot 2.1.2 a/Spring Data Lovelace SR4에 추가된 확장함수이다.
Kotlin Nullable 객체를 받을 수 있도록 지원해주고 있다.
이 함수의 내부 구현을 보면 아주 심플하게 구현된 것을 확인할 수 있는데,
fun <T, ID> CrudRepository<T, ID>.findByIdOrNull(id: ID): T? = findById(id).orElse(null)
결국 Optional을 사용해서 구현된 확장함수라는 것을 알 수 있다.
만약 이러한 Optional을 래핑하는 것이 성능상의 이유로 꺼려진다면 다른 방법이 있다.
2. JPA Repository에 사용자 정의 인터페이스를 추가한다.
어떻게 보면 가장 간단한 방법인데, JpaRepository에 다음과 같이 사용자 정의 인터페이스를 만들면 내부적으로 코틀린 타입을 반환해주기 때문에 Optional에 대한 성능적 저하를 피할 수 있다.
interface PostRepository: JpaRepository<Post,Long>{
fun findPostById(id: Long): Post?
}
val post = Post(
null,
"테스트용"
)
val savePost = postRepository.save(post)
// val findPost = postRepository.findByIdOrNull(savePost.id) ?: return
val findPost = postRepository.findPostById(savePost.id!!) ?: return
println(findPost::class.simpleName)
하지만 Optional을 사용하는 것의 성능적 저하는 거의 없기 때문에 사실상 1번의 방법을 가장 추천한다고 한다.
어떤 것을 사용할지는 개발자의 마음이다.
다만, 개인적인 생각으로는 1번의 방법이 더 친숙하게 보인다.
그리고 이러한 업데이트는 Spring에서도 공식적으로 Kotlin을 지원해주기 위한 기능들이 추가되고 있다는 사실이고, 서버사이드에서도 코틀린이 자바의 자리를 대체할 수 있을거라고 보여진다.
Reference
https://stackoverflow.com/questions/47143127/spring-data-jpa-how-to-use-kotlin-nulls-instead-of-optional