Application fails to start when eactive restclient uses both ClientExceptionMapper and ClientObjectMapper #35884
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