Having this piece of code (simplified):
Value class:
@JvmInline
value class Foo(val value: String)
Entity:
@Entity
class Bar {
@Id
var id: Long = 0L
var foo: Foo = Foo("")
}
Repository:
interface BarRepository : JpaRepository<Bar, Long> {
@Query("select b from Bar b where b.foo = :foo")
fun findByFoo(foo: Foo): List<Bar>
@Query("select b from Bar b where b.foo in (:fooList)")
fun findByFooIn(fooList: List<Foo>): List<Bar>
}
The first query will work, but the other one will fail with JPA complaining that it was expecting a list of String-s, but got a list of Foo-s.
If I change the signature so that fooList becomes List (and map input to list of strings) it works, but of course, then I will lose type checking.
My question is why does it work with a single item, but fails with a list, and if anyone is aware of a workaround (other than using strings explicitly).
1 Like
Did you find any satisfactory answer? The same problem happens when you need to return a Set
of Foo
.
As long as you don’t use any additional invariants in your type I would recommend using aliases instead. Kotlin’s value classes don’t work so well in Java-originated libraries and technologies because of boxing issue.
Another advice for you would be to separate JPA model from your business model, REST model, etc. Then you could stick to value classes anywere as long as you map them once from a database model.
This is just a guess, not an actual answer.
My guess is that because Foo
is used as the type parameter of a List
, the compiler might be overlooking it for the inline replacement. I wonder if you could decompile the JVM Bytecode to Java code and see what that interface looks like.
Ok I think it’s this thing: Inline value classes | Kotlin Documentation
If I’m understanding it correctly, in places where the value class is used directly, it’s replaced with the real type. But in places where a generic is used, the value class is used instead of the real type, I think.