Skip to content

Application fails to start when eactive restclient uses both ClientExceptionMapper and ClientObjectMapper #35884

Closed
@manofthepeace

Description

Describe the bug

When a reactive rest client interface contains both @ClientExceptionMapper and @ClientObjectMapper the application fails to start with the following;

2023-09-12 10:17:39,218 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerProvidersFromAnnotations threw an exception: java.lang.IllegalStateException: Only a single instance of 'io.quarkus.rest.client.reactive.jackson.ClientObjectMapper' is allowed per REST Client interface. Offending class is 'org.acme.MyRestClient'
	at io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor.populateClientProviderFromAnnotations(RestClientReactiveProcessor.java:613)
	at io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor.registerProvidersFromAnnotations(RestClientReactiveProcessor.java:338)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:858)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:282)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
	at java.base/java.lang.Thread.run(Thread.java:833)
	at org.jboss.threads.JBossThread.run(JBossThread.java:501)

	at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:336)
	at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:253)
	at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:60)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:82)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:423)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:55)
	at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:138)
	at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:93)
	at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:131)
	at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:62)
Caused by: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor#registerProvidersFromAnnotations threw an exception: java.lang.IllegalStateException: Only a single instance of 'io.quarkus.rest.client.reactive.jackson.ClientObjectMapper' is allowed per REST Client interface. Offending class is 'org.acme.MyRestClient'
	at io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor.populateClientProviderFromAnnotations(RestClientReactiveProcessor.java:613)
	at io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor.registerProvidersFromAnnotations(RestClientReactiveProcessor.java:338)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:858)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:282)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
	at java.base/java.lang.Thread.run(Thread.java:833)
	at org.jboss.threads.JBossThread.run(JBossThread.java:501)

	at io.quarkus.builder.Execution.run(Execution.java:123)
	at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:79)
	at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:160)
	at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:332)
	... 9 more
Caused by: java.lang.IllegalStateException: Only a single instance of 'io.quarkus.rest.client.reactive.jackson.ClientObjectMapper' is allowed per REST Client interface. Offending class is 'org.acme.MyRestClient'
	at io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor.populateClientProviderFromAnnotations(RestClientReactiveProcessor.java:613)
	at io.quarkus.rest.client.reactive.deployment.RestClientReactiveProcessor.registerProvidersFromAnnotations(RestClientReactiveProcessor.java:338)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.deployment.ExtensionLoader$3.execute(ExtensionLoader.java:858)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:282)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1538)
	at java.base/java.lang.Thread.run(Thread.java:833)
	at org.jboss.threads.JBossThread.run(JBossThread.java:501)

It seems to be because RestClientReactiveProcessor::populateClientProviderFromAnnotations uses the same Map<String, GeneratedClassResult> generatedProviders where the key is the interface name. So once it deals with the exceptions mapper, it gets added to the map, and fails in the provider section. I am not sure the best way to fix, besides changing the key to class_annotation?

Expected behavior

Application should start wieh both annotations

Actual behavior

application fails to start.

How to Reproduce?

Reproducer: https://github.com/manofthepeace/quarkus-restclient-annotations-issue

Steps tp reproduce;
1- mvn quarkus:dev (will fail)

Output of uname -a or ver

Darwin Kernel Version 21.6.0

Output of java -version

OpenJDK 64-Bit Server VM Temurin-17.0.8.1+1

GraalVM version (if different from Java)

n/a

Quarkus version or git rev

3.3.2

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

3.9.1

Additional information

No response

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions