ClassCastException in ReactiveEmbeddableInitializerImpl when using an EmbeddedId which contains a reference to another entity
Describe the bug
Given a setup where I have an entity FooEntity which has an EmbeddedId FooId, and FooId contains a reference to BarEntity, then trying to query FooEntity through Panache causes the following ClassCastException:
[ERROR] org.acme.hibernate.orm.panache.ReproTest.test(TransactionalUniAsserter) -- Time elapsed: 0.124 s <<< ERROR!
java.lang.ClassCastException: class org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer cannot be cast to class org.hibernate.reactive.sql.results.graph.ReactiveInitializer (org.hibernate.sql.results.graph.entity.internal.EntitySelectFetchInitializer and org.hibernate.reactive.sql.results.graph.ReactiveInitializer are in unnamed module of loader io.quarkus.bootstrap.classloading.QuarkusClassLoader @4cc7d00d)
at org.hibernate.reactive.sql.results.graph.embeddable.internal.ReactiveEmbeddableInitializerImpl.lambda$forEachReactiveSubInitializer$0(ReactiveEmbeddableInitializerImpl.java:75)
at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$2(CompletionStages.java:175)
at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$7(CompletionStages.java:410)
at org.hibernate.reactive.util.impl.CompletionStages$ArrayLoop.next(CompletionStages.java:484)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.lambda$asyncWhile$1(AsyncTrampoline.java:215)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.unroll(AsyncTrampoline.java:121)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.trampoline(AsyncTrampoline.java:102)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:197)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:215)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:411)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:382)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:175)
at org.hibernate.reactive.sql.results.graph.embeddable.internal.ReactiveEmbeddableInitializerImpl.lambda$forEachReactiveSubInitializer$1(ReactiveEmbeddableInitializerImpl.java:74)
at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$2(CompletionStages.java:175)
at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$7(CompletionStages.java:410)
at org.hibernate.reactive.util.impl.CompletionStages$ArrayLoop.next(CompletionStages.java:484)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.lambda$asyncWhile$1(AsyncTrampoline.java:215)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.unroll(AsyncTrampoline.java:121)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.trampoline(AsyncTrampoline.java:102)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:197)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:215)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:411)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:382)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:175)
at org.hibernate.reactive.sql.results.graph.embeddable.internal.ReactiveEmbeddableInitializerImpl.forEachReactiveSubInitializer(ReactiveEmbeddableInitializerImpl.java:74)
at org.hibernate.reactive.sql.results.graph.ReactiveInitializer.reactiveResolveKey(ReactiveInitializer.java:36)
at org.hibernate.reactive.sql.results.graph.entity.internal.ReactiveEntityInitializerImpl.initializeId(ReactiveEntityInitializerImpl.java:749)
at org.hibernate.reactive.sql.results.graph.entity.internal.ReactiveEntityInitializerImpl.reactiveResolveKey(ReactiveEntityInitializerImpl.java:625)
at org.hibernate.reactive.sql.results.graph.entity.internal.ReactiveEntityInitializerImpl.reactiveResolveKey(ReactiveEntityInitializerImpl.java:605)
at org.hibernate.reactive.sql.results.graph.entity.internal.ReactiveEntityInitializerImpl.reactiveResolveKey(ReactiveEntityInitializerImpl.java:56)
at org.hibernate.reactive.sql.results.internal.ReactiveStandardRowReader.resolveKey(ReactiveStandardRowReader.java:383)
at org.hibernate.reactive.sql.results.internal.ReactiveStandardRowReader.lambda$coordinateInitializers$28(ReactiveStandardRowReader.java:376)
at org.hibernate.reactive.util.impl.CompletionStages.lambda$loop$7(CompletionStages.java:410)
at org.hibernate.reactive.util.impl.CompletionStages$ArrayLoop.next(CompletionStages.java:484)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.lambda$asyncWhile$1(AsyncTrampoline.java:215)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.unroll(AsyncTrampoline.java:121)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline$TrampolineInternal.trampoline(AsyncTrampoline.java:102)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:197)
at org.hibernate.reactive.util.async.impl.AsyncTrampoline.asyncWhile(AsyncTrampoline.java:215)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:411)
at org.hibernate.reactive.util.impl.CompletionStages.loop(CompletionStages.java:382)
at org.hibernate.reactive.sql.results.internal.ReactiveStandardRowReader.coordinateInitializers(ReactiveStandardRowReader.java:376)
at org.hibernate.reactive.sql.results.internal.ReactiveStandardRowReader.reactiveReadRow(ReactiveStandardRowReader.java:126)
at org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.lambda$addToResultsSupplier$5(ReactiveListResultsConsumer.java:141)
at org.hibernate.reactive.sql.results.spi.ReactiveListResultsConsumer.lambda$consume$1(ReactiveListResultsConsumer.java:96)
at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1150)
at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:510)
at java.base/java.util.concurrent.CompletableFuture.complete(CompletableFuture.java:2179)
at io.vertx.core.Future.lambda$toCompletionStage$3(Future.java:602)
at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:66)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:259)
at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:88)
at io.vertx.sqlclient.impl.QueryResultBuilder.tryComplete(QueryResultBuilder.java:32)
at io.vertx.core.Promise.complete(Promise.java:66)
at io.vertx.core.Promise.handle(Promise.java:51)
at io.vertx.core.Promise.handle(Promise.java:29)
at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:66)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:259)
at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:41)
at io.vertx.sqlclient.impl.TransactionImpl.lambda$wrap$0(TransactionImpl.java:72)
at io.vertx.core.impl.future.FutureImpl$4.onSuccess(FutureImpl.java:176)
at io.vertx.core.impl.future.FutureBase.lambda$emitSuccess$0(FutureBase.java:60)
at io.vertx.core.impl.ContextImpl.execute(ContextImpl.java:312)
at io.vertx.core.impl.DuplicatedContext.execute(DuplicatedContext.java:168)
at io.vertx.core.impl.future.FutureBase.emitSuccess(FutureBase.java:57)
at io.vertx.core.impl.future.FutureImpl.tryComplete(FutureImpl.java:259)
at io.vertx.core.impl.future.PromiseImpl.onSuccess(PromiseImpl.java:49)
at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:41)
at io.vertx.core.impl.future.PromiseImpl.handle(PromiseImpl.java:23)
at io.vertx.sqlclient.impl.command.CommandResponse.fire(CommandResponse.java:46)
at io.vertx.sqlclient.impl.SocketConnectionBase.handleMessage(SocketConnectionBase.java:324)
at io.vertx.pgclient.impl.PgSocketConnection.handleMessage(PgSocketConnection.java:114)
at io.vertx.sqlclient.impl.SocketConnectionBase.lambda$init$0(SocketConnectionBase.java:137)
at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:342)
at io.vertx.core.impl.ContextImpl.emit(ContextImpl.java:335)
at io.vertx.core.net.impl.NetSocketImpl.handleMessage(NetSocketImpl.java:389)
at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:159)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:153)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
at io.vertx.pgclient.impl.codec.PgDecoder.fireCommandResponse(PgDecoder.java:52)
at io.vertx.pgclient.impl.codec.PgCommandCodec.handleReadyForQuery(PgCommandCodec.java:133)
at io.vertx.pgclient.impl.codec.PgDecoder.decodeReadyForQuery(PgDecoder.java:248)
at io.vertx.pgclient.impl.codec.PgDecoder.channelRead(PgDecoder.java:107)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:868)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:796)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:732)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:998)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:1583)
Expected behavior
No exception is thrown, and querying FooEntity behaves as expected.
Actual behavior
The aforementioned exception is unexpectedly thrown
How to Reproduce?
Running ReproducerTest in the attached reproducer archive reproduces the error. Can use ./mvnw integration-test -Dtest=ReproducerTest
class_cast_bug_quarkus_reproducer.zip
Output of uname -a or ver
Darwin MACHINE_NAME 24.4.0 Darwin Kernel Version 24.4.0: Wed Mar 19 21:17:25 PDT 2025; root:xnu-11417.101.15~1/RELEASE_ARM64_T6020 arm64
Output of java -version
openjdk version "21.0.6" 2025-01-21 LTS OpenJDK Runtime Environment Corretto-21.0.6.7.1 (build 21.0.6+7-LTS) OpenJDK 64-Bit Server VM Corretto-21.0.6.7.1 (build 21.0.6+7-LTS, mixed mode, sharing)
Quarkus version or git rev
3.20.0
Build tool (ie. output of mvnw --version or gradlew --version)
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Additional information
No response
/cc @gsmet (hibernate-orm)
cc @DavideD
This is a bug in Hibernate Reactive, I'm looking into it
Thanks for the feedback!
I've created this issue for Hibernate Reactive: https://github.com/hibernate/hibernate-reactive/issues/2230 Not sure when I can start to look into it, though