Kotlin value class 를 사용하려면 어떻게 해야할까요?
엔티티의 프로퍼티를 kotlin의 value class로 선언할 수 있습니다.
@Entity
class User(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: UserId = UserId(0),
)
@JvmInline
value class UserId(private val value: Long)
@Service
class UserService(
private val jpqlRenderContext: JpqlRenderContext,
private val entityManager: EntityManager,
) {
fun findById(userId: UserId): User? {
val query = jpql {
select(
entity(User::class)
).from(
entity(User::class),
).where(
path(User::id).equal(userId)
)
}
return entityManager.createQuery(query, jpqlRenderContext).apply { maxResults = 1 }.resultList.firstOrNull()
}
}하지만 추가적인 설정 없이 Hibernate를 사용해 Kotlin JDSL을 통해 조회하면 에러가 발생합니다.
이를 해결하려면 Kotlin JDSL이 매개 변수로 전달되는 value class의 unboxing이 필요합니다. unboxing은 다음 방안 중 하나를 선택해서 수행할 수 있습니다.
JpqlValue용 커스텀 JpqlSerializer
에러를 해결하기 위해 EntityManager에 인자들을 value class 그 자체로 넘기지 않고 unboxing한 값을 넘겨야합니다. Kotlin JDSL은 JpqlValueSerializer 클래스에서 인자들을 추출하는 역할을 담당합니다. 따라서 기본 제공하는 클래스 대신 커스텀 Seriailzer를 등록해야 합니다.
먼저 다음과 같은 커스텀 Seriailzer를 생성합니다.
이제 이 클래스를 RenderContext에 추가해야 합니다. 추가하는 방법은 다음 문서를 참조할 수 있습니다. 만약 스프링 부트를 사용하는 경우 다음과 같은 코드를 통해 커스텀 Seriziler를 Bean으로 등록하면 됩니다.
custom method 사용
Kotlin JDSL에서 제공하는 custom dsl 사용해 value class 에 사용되는 매서드를 추가할 수 있습니다.
interface 도입과 오버로딩을 통해 다양한 value class에 대응할 수 있습니다.
DTO Projection 시 주의사항
DTO Projection 에서 value class를 사용하는 경우 해당 프로퍼티가 nullable 한 경우에 지원되지 않습니다. 따라서 DTO Projection에서 직접 value class를 사용하는 것보다, 기본 자료형을 사용하고 조회 후에 변환하는 것을 권장합니다.
Last updated