quarkus: Quarkus 3/Hibernate ORM 6: entity inheritance does not work with Kotlin
Describe the bug
Using Hibernate entity inheritance with Kotlin works fine with Quarkus 2 but not with Quarkus 3.
I’ve created a repo that reproduce the bug: https://github.com/cthiebault/quarkus-hibernate-kotlin
Use the quarkus2
and quarkus3
branches to reproduce the issue.
Here are the entities
@Entity
@Table(name = "shape")
@Inheritance(strategy = InheritanceType.JOINED)
abstract class Shape(
@Id
@JdbcTypeCode(SqlTypes.VARCHAR)
@Column(name = "id", updatable = false, nullable = false, unique = true)
open val id: UUID,
@Length(max = 100)
@Column(name = "name", nullable = false, length = 100)
open var name: String,
@Enumerated(EnumType.STRING)
@Column(name = "color", nullable = false, length = 50)
open var color: Color,
@Embedded
var properties: Properties?,
)
@Entity
@Table(name = "rectangle")
@PrimaryKeyJoinColumn(name = "shape_id")
data class Rectangle(
override val id: UUID,
override var name: String,
override var color: Color,
override var properties: Properties?
) : Shape(id, name, color, properties)
@ApplicationScoped
class ShapeRepository : PanacheRepositoryBase<Shape, UUID>
And the test I run
@Test
@Transactional
fun test() {
val rectangle = Rectangle(
id = UUID.randomUUID(),
name = "Rectangle",
color = Color.Red,
properties = Properties("foo", "bar")
)
Log.info("rectangle: $rectangle")
repository.persist(rectangle)
val found = repository.findById(rectangle.id)
Log.info("found: $found")
assertEquals(rectangle, found)
assertEquals(1, repository.count())
}
The error with Qurakus 3:
INFO: rectangle: Rectangle(id=7c0863fb-a786-4dd7-b9f1-c3b3f48fc0d8, name=Rectangle, color=Red, properties=Properties(foo=foo, bar=bar))
INFO: found: Rectangle(id=7c0863fb-a786-4dd7-b9f1-c3b3f48fc0d8, name=Rectangle, color=Red, properties=Properties(foo=foo, bar=bar))
ERROR: ERROR: null value in column "name" of relation "shape" violates not-null constraint
Detail: Failing row contains (7c0863fb-a786-4dd7-b9f1-c3b3f48fc0d8, null, null, null, null).
could not execute statement [ERROR: null value in column "name" of relation "shape" violates not-null constraint
Detail: Failing row contains (7c0863fb-a786-4dd7-b9f1-c3b3f48fc0d8, null, null, null, null).] [insert into shape (color,name,bar,foo,id) values (?,?,?,?,?)]
org.hibernate.exception.ConstraintViolationException: could not execute statement [ERROR: null value in column "name" of relation "shape" violates not-null constraint
Detail: Failing row contains (7c0863fb-a786-4dd7-b9f1-c3b3f48fc0d8, null, null, null, null).] [insert into shape (color,name,bar,foo,id) values (?,?,?,?,?)]
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:95)
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:56)
at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:108)
at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:278)
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.performNonBatchedMutation(AbstractMutationExecutor.java:108)
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorStandard.lambda$performNonBatchedOperations$1(MutationExecutorStandard.java:217)
at java.base@17.0.7/java.util.TreeMap.forEach(TreeMap.java:1282)
at org.hibernate.engine.jdbc.mutation.internal.PreparedStatementGroupStandard.forEachStatement(PreparedStatementGroupStandard.java:90)
at org.hibernate.engine.jdbc.mutation.internal.MutationExecutorStandard.performNonBatchedOperations(MutationExecutorStandard.java:217)
at org.hibernate.engine.jdbc.mutation.internal.AbstractMutationExecutor.execute(AbstractMutationExecutor.java:53)
at org.hibernate.persister.entity.mutation.InsertCoordinator.doStaticInserts(InsertCoordinator.java:170)
at org.hibernate.persister.entity.mutation.InsertCoordinator.coordinateInsert(InsertCoordinator.java:112)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2656)
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:102)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:616)
at org.hibernate.engine.spi.ActionQueue.lambda$executeActions$1(ActionQueue.java:487)
at java.base@17.0.7/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:484)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:358)
at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:55)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1375)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.lambda$new$0(ConcreteSqmSelectQueryPlan.java:107)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.withCacheableSqmInterpretation(ConcreteSqmSelectQueryPlan.java:302)
at org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan.performList(ConcreteSqmSelectQueryPlan.java:243)
at org.hibernate.query.sqm.internal.QuerySqmImpl.doList(QuerySqmImpl.java:521)
at org.hibernate.query.spi.AbstractSelectionQuery.list(AbstractSelectionQuery.java:367)
at org.hibernate.query.sqm.internal.QuerySqmImpl.list(QuerySqmImpl.java:1084)
at org.hibernate.query.spi.AbstractSelectionQuery.getSingleResult(AbstractSelectionQuery.java:461)
at org.hibernate.query.sqm.internal.QuerySqmImpl.getSingleResult(QuerySqmImpl.java:1110)
at io.quarkus.hibernate.orm.panache.common.runtime.AbstractJpaOperations.count(AbstractJpaOperations.java:323)
at org.acme.ShapeRepository.count(ShapeRepository.kt)
at org.acme.ShapeRepository_ClientProxy.count(Unknown Source)
at org.acme.ShapeTest.test(ShapeTest.kt:43)
Expected behavior
No response
Actual behavior
No response
How to Reproduce?
https://github.com/cthiebault/quarkus-hibernate-kotlin
Output of uname -a
or ver
No response
Output of java -version
No response
GraalVM version (if different from Java)
No response
Quarkus version or git rev
No response
Build tool (ie. output of mvnw --version
or gradlew --version
)
No response
Additional information
Gradle 8.1.1 Build time: 2023-04-21 12:31:26 UTC Revision: 1cf537a851c635c364a4214885f8b9798051175b
Kotlin: 1.8.10 Groovy: 3.0.15 Ant: Apache Ant™ version 1.10.11 compiled on July 10 2021 JVM: 17.0.7 (Eclipse Adoptium 17.0.7+7) OS: Linux 6.1.30-1-MANJARO amd64
About this issue
- Original URL
- State: open
- Created a year ago
- Comments: 21 (11 by maintainers)
Not in 3.2.0, since core artifacts have already been released. It’ll be fixed next time we upgrade Hibernate ORM in Quarkus. Probably in 3.2.1/3.2.2.
You would need a backport of HHH-16593 to Hibernate ORM 6.2, which from what I understand is unlikely unless you have a support contract: https://hibernate.org/orm/releases/6.2/ , https://hibernate.org/community/maintenance-policy/#levels . You can always ask the Hibernate ORM team though 🤷
As for Quarkus, this will get fixed when we upgrade to Hibernate ORM 6.3/6.4, which I’m currently working on. So this should hopefully be in Quarkus 3.6, or Quarkus 3.7 if we don’t get a Hibernate Reactive release in time.
Can we get this functionality merged in Quarkus 3.2.8 Final?
@cthiebault, thanks again for reporting a problem. As it turned out, it is a different bug from the one about Kotlin. I’ve created this ticket for it: https://hibernate.atlassian.net/browse/HHH-16799 I couldn’t see any workarounds for you, so it seems you’d need to stay on 3.1.0 for now.
Yes, sure. Will do 👍🏻😃
@cthiebault As stated above, this is a bug in Hibernate ORM.
If things still don’t work, or are getting worse, I’d recommend reaching out to the Hibernate ORM team, in particular to assist in analyzing the causes on the Kotlin side of things. Christian asked for just that here.
Glad to hear that.
FWIW, you should be able to put the annotation at the type level:
Created https://hibernate.atlassian.net/browse/HHH-16735 ( reported earlier https://hibernate.atlassian.net/browse/HHH-15874)
Also tested your suggestion about
@Access(AccessType.PROPERTY)
– that helps:makes the test pass.
Can you please create an issue in Hibernate ORM? Though I’m not sure this will get a high priority given Hibernate ORM mostly targets Java and not Kotlin…
I would guess this has to do with Kotlin’s property override? Most likely field access won’t work well in such case, since, well… Kotlin probably just never uses the parent class’ field.
I’d suggest trying to avoid field override and seeing where this leads.
Failing that, putting
@Access(AccessType.PROPERTY)
onShape
orRectangle
could be a valid workaround, assuming Kotlin goes generate getters and setters (getId()
, etc.). Someone would have to try, though.