Skip to content

REST Client fails for sub-resources with BeanParam #47821

@jburkal

Description

@jburkal

Describe the bug

Since Quarkus 3.21.3, REST client interfaces fails to initialize if they have any methods with a @BeanParam annotated parameter that returns a sub-resource interface. The following exception is thrown:

java.lang.RuntimeException: Error injecting org.acme.subresourcebean.TestClient org.acme.subresourcebean.TestResource.client
        at org.acme.subresourcebean.TestResource_Bean.doCreate(Unknown Source)
        at org.acme.subresourcebean.TestResource_Bean.create(Unknown Source)
        at org.acme.subresourcebean.TestResource_Bean.create(Unknown Source)
        at io.quarkus.arc.impl.AbstractSharedContext.createInstanceHandle(AbstractSharedContext.java:119)
        at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:38)
        at io.quarkus.arc.impl.AbstractSharedContext$1.get(AbstractSharedContext.java:35)
        at io.quarkus.arc.impl.LazyValue.get(LazyValue.java:32)
        at io.quarkus.arc.impl.ComputingCache.computeIfAbsent(ComputingCache.java:69)
        at io.quarkus.arc.impl.ComputingCacheContextInstances.computeIfAbsent(ComputingCacheContextInstances.java:19)
        at io.quarkus.arc.impl.AbstractSharedContext.get(AbstractSharedContext.java:35)
        at org.acme.subresourcebean.TestResource_Bean.get(Unknown Source)
        at org.acme.subresourcebean.TestResource_Bean.get(Unknown Source)
        at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:570)
        at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:550)
        at io.quarkus.arc.impl.ArcContainerImpl.beanInstanceHandle(ArcContainerImpl.java:583)
        at io.quarkus.arc.impl.ArcContainerImpl$3.get(ArcContainerImpl.java:337)
        at io.quarkus.arc.impl.ArcContainerImpl$3.get(ArcContainerImpl.java:334)
        at io.quarkus.arc.runtime.BeanContainerImpl$1.create(BeanContainerImpl.java:62)
        at io.quarkus.resteasy.reactive.common.runtime.ArcBeanFactory.createInstance(ArcBeanFactory.java:27)
        at org.jboss.resteasy.reactive.server.handlers.InstanceHandler.handle(InstanceHandler.java:26)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:139)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:638)
        at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
        at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:840)
Caused by: org.eclipse.microprofile.rest.client.RestClientDefinitionException: org.jboss.resteasy.reactive.client.api.InvalidRestClientDefinitionException: Failed to generate client for class interface org.acme.subresourcebean.TestClient : Must be a Class or String, got null
        at io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl.build(RestClientBuilderImpl.java:595)
        at io.quarkus.rest.client.reactive.runtime.QuarkusRestClientBuilderImpl.build(QuarkusRestClientBuilderImpl.java:279)
        at io.quarkus.rest.client.reactive.runtime.RestClientCDIDelegateBuilder.build(RestClientCDIDelegateBuilder.java:74)
        at io.quarkus.rest.client.reactive.runtime.RestClientCDIDelegateBuilder.createDelegate(RestClientCDIDelegateBuilder.java:54)
        at io.quarkus.rest.client.reactive.runtime.RestClientReactiveCDIWrapperBase.delegate(RestClientReactiveCDIWrapperBase.java:76)
        at io.quarkus.rest.client.reactive.runtime.RestClientReactiveCDIWrapperBase.<init>(RestClientReactiveCDIWrapperBase.java:30)
        at org.acme.subresourcebean.TestClient$$CDIWrapper.<init>(Unknown Source)
        at org.acme.subresourcebean.TestClient$$CDIWrapper_ClientProxy.<init>(Unknown Source)
        at org.acme.subresourcebean.TestClient$$CDIWrapper_Bean.proxy(Unknown Source)
        ... 31 more
Caused by: org.jboss.resteasy.reactive.client.api.InvalidRestClientDefinitionException: Failed to generate client for class interface org.acme.subresourcebean.TestClient : Must be a Class or String, got null
        at org.jboss.resteasy.reactive.client.impl.ClientProxies.get(ClientProxies.java:31)
        at org.jboss.resteasy.reactive.client.impl.WebTargetImpl.proxy(WebTargetImpl.java:465)
        at io.quarkus.rest.client.reactive.runtime.RestClientBuilderImpl.build(RestClientBuilderImpl.java:593)
        ... 41 more

The cause of this exception happens at build time, but does not cause a build failure:

2025-05-12 09:14:21,323 DEBUG [io.qua.jax.cli.rea.dep.JaxrsClientReactiveProcessor] (build-10) Failed to create client proxy for org.acme.subresourcebean.TestClient this can usually be safely ignored: java.lang.IllegalArgumentException: Must be a Class or String, got null
        at io.quarkus.gizmo.DescriptorUtils.objectToDescriptor(DescriptorUtils.java:133)
        at io.quarkus.gizmo.FieldDescriptor.of(FieldDescriptor.java:44)
        at io.quarkus.gizmo.ClassCreator.getFieldCreator(ClassCreator.java:126)
        at io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveProcessor.handleSubResourceMethod(JaxrsClientReactiveProcessor.java:1551)
        at io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveProcessor.generateClientInvoker(JaxrsClientReactiveProcessor.java:932)
        at io.quarkus.jaxrs.client.reactive.deployment.JaxrsClientReactiveProcessor.setupClientProxies(JaxrsClientReactiveProcessor.java:423)
        at java.base/java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:732)
        at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:856)
        at io.quarkus.builder.BuildContext.run(BuildContext.java:255)
        at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
        at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2675)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2654)
        at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1627)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1594)
        at java.base/java.lang.Thread.run(Thread.java:840)
        at org.jboss.threads.JBossThread.run(JBossThread.java:499)

This used to work, but has failed since Quarkus version 3.21.3.

The most likely cause Is the changes introduced in #47368, specifically changing param.type to param.declaredType in the JaxrsClientReactiveProcessor#handleSubResourceMethod method.

Looking at this with a debugger, I can see that the declaredType field on the FieldDescriptor object is null, whereas the type field contains the correct class name.

Expected behavior

No response

Actual behavior

No response

How to Reproduce?

I've created a GitHub repository that reproduces this problem: https://github.com/jburkal/quarkus-beanparam-test

Specifically:

Output of uname -a or ver

No response

Output of java -version

No response

Quarkus version or git rev

3.21.3

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions