kotlin-jdsl
kotlin-jdsl copied to clipboard
Is it possible to support rendering query that contains entities with `value class` fields?
spring data add support for kotlin value class at version 3.2 , so we can define an entity like this to avoid primitive obsession:
import jakarta.persistence.*
@Entity
class Brand(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: BrandId = BrandId(0),
val name: String,
) {
@Version
val version: Int = 0
}
@JvmInline
value class BrandId(private val value: Long) : Comparable<BrandId> { // jdsl Expressionable.gt requires type implements Comparable
override fun compareTo(other: BrandId): Int =
value.compareTo(other.value)
}
@Entity
class Product(
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
val id: ProductId = ProductId(0),
val name: String,
@Enumerated(EnumType.STRING)
val type: ProductType,
val brandId: BrandId,
) {
@Version
val version: Int = 0
}
@JvmInline
value class ProductId(val value: Long)
enum class ProductType {
DRINK,
TOOL,
FOOD
}
and saying that there is a simple query
data class ProductWithBrand(
val productId: ProductId,
val productName: String,
val brandId: BrandId,
val brandName: String,
)
@Service
class TestService(
private val jpqlRenderContext: JpqlRenderContext,
private val entityManager: EntityManager,
) {
fun test(): List<ProductWithBrand> {
val query = jpql {
select<ProductWithBrand>(
path(Product::id),
path(Product::name),
path(Brand::id),
path(Brand::name),
)
.from(
entity(Product::class),
join(Brand::class).on(path(Product::brandId).eq(path(Brand::id)))
)
.where(
entity(Product::class)(Product::name).like("coca")
.or(
path(Brand::name).eq("a")
.and(path(Brand::id).gt(BrandId(1L)))
)
)
.orderBy(path(Product::id).desc())
}
return entityManager.createQuery(query, jpqlRenderContext).apply { maxResults = 1 }.resultList
}
}
and got an exception when executing it
org.hibernate.type.descriptor.java.CoercionException: Cannot coerce value 'BrandId(value=1)' [com.example.springpg.entity.BrandId] to Long
at org.hibernate.type.descriptor.java.LongJavaType.coerce(LongJavaType.java:157) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.type.descriptor.java.LongJavaType.coerce(LongJavaType.java:24) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.query.internal.QueryParameterBindingImpl.coerce(QueryParameterBindingImpl.java:164) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.query.internal.QueryParameterBindingImpl.setBindValue(QueryParameterBindingImpl.java:113) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.query.spi.AbstractCommonQueryContract.setParameter(AbstractCommonQueryContract.java:835) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.query.spi.AbstractSelectionQuery.setParameter(AbstractSelectionQuery.java:900) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.query.sqm.internal.QuerySqmImpl.setParameter(QuerySqmImpl.java:1258) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at org.hibernate.query.sqm.internal.QuerySqmImpl.setParameter(QuerySqmImpl.java:140) ~[hibernate-core-6.4.1.Final.jar:6.4.1.Final]
at com.linecorp.kotlinjdsl.support.spring.data.jpa.JpqlEntityManagerUtils.setParams(JpqlEntityManagerUtils.kt:220) ~[spring-data-jpa-support-3.2.0.jar:na]
at com.linecorp.kotlinjdsl.support.spring.data.jpa.JpqlEntityManagerUtils.createQuery(JpqlEntityManagerUtils.kt:92) ~[spring-data-jpa-support-3.2.0.jar:na]
at com.linecorp.kotlinjdsl.support.spring.data.jpa.JpqlEntityManagerUtils.createQuery(JpqlEntityManagerUtils.kt:30) ~[spring-data-jpa-support-3.2.0.jar:na]
at com.linecorp.kotlinjdsl.support.spring.data.jpa.extension.EntityManagerExtensionsKt.createQuery(EntityManagerExtensions.kt:20) ~[spring-data-jpa-support-3.2.0.jar:na]
at com.example.springpg.service.TestService.test(TestService.kt:41) ~[main/:na]
at com.example.springpg.SpringPgApplication$route$1$1$1.invoke(SpringPgApplication.kt:25) ~[main/:na]
at com.example.springpg.SpringPgApplication$route$1$1$1.invoke(SpringPgApplication.kt:24) ~[main/:na]
at org.springframework.web.servlet.function.RouterFunctionDsl.GET$lambda$0(RouterFunctionDsl.kt:153) ~[spring-webmvc-6.1.2.jar:6.1.2]
at org.springframework.web.servlet.function.support.HandlerFunctionAdapter.handle(HandlerFunctionAdapter.java:107) ~[spring-webmvc-6.1.2.jar:6.1.2]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1089) ~[spring-webmvc-6.1.2.jar:6.1.2]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:979) ~[spring-webmvc-6.1.2.jar:6.1.2]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014) ~[spring-webmvc-6.1.2.jar:6.1.2]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903) ~[spring-webmvc-6.1.2.jar:6.1.2]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564) ~[tomcat-embed-core-10.1.17.jar:6.0]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885) ~[spring-webmvc-6.1.2.jar:6.1.2]
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658) ~[tomcat-embed-core-10.1.17.jar:6.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-10.1.17.jar:10.1.17]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.2.jar:6.1.2]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.2.jar:6.1.2]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-6.1.2.jar:6.1.2]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116) ~[spring-web-6.1.2.jar:6.1.2]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:340) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:896) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1744) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-10.1.17.jar:10.1.17]
at java.base/java.lang.VirtualThread.run(VirtualThread.java:309) ~[na:na]