Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reactive-rest-data not compliant with openapi #25990

Closed
doublefx opened this issue Jun 7, 2022 · 9 comments · Fixed by #26074
Closed

reactive-rest-data not compliant with openapi #25990

doublefx opened this issue Jun 7, 2022 · 9 comments · Fixed by #26074
Labels
area/openapi area/smallrye env/windows Impacts Windows machines kind/bug Something isn't working
Milestone

Comments

@doublefx
Copy link

doublefx commented Jun 7, 2022

Describe the bug

Adding quarkus-smallrye-openapi + quarkus-hibernate-reactive-rest-data-panache prevent the service to start

It looks like the generated methods return a Uni.class and not a parameterized type Uni<> which fails open-api-core/AnnotationScanner when checking for TypeUtil.unwrapType(returnType) in isVoidResponse.

Can't we generate a parameterized Uni<Void/Object> method signature with gizmo ?

Expected behavior

Service should start and work with openapi

Actual behavior

2022-06-07 15:20:23,089 INFO  [org.jbo.threads] (main) JBoss Threads version 3.4.2.Final
2022-06-07 15:20:24,043 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.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#build threw an exception: java.lang.IllegalArgumentException: Not a parameterized type!
	at org.jboss.jandex.Type.asParameterizedType(Type.java:228)
	at io.smallrye.openapi.runtime.util.TypeUtil.unwrapType(TypeUtil.java:521)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.isVoidResponse(AnnotationScanner.java:502)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.getDefaultStatus(AnnotationScanner.java:476)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.createResponseFromRestMethod(AnnotationScanner.java:403)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.processResponse(AnnotationScanner.java:360)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceMethod(JaxRsAnnotationScanner.java:443)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.lambda$processResourceMethods$0(JaxRsAnnotationScanner.java:279)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceMethods(JaxRsAnnotationScanner.java:277)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceClass(JaxRsAnnotationScanner.java:247)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceClasses(JaxRsAnnotationScanner.java:222)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.scan(JaxRsAnnotationScanner.java:154)
	at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.scan(OpenApiAnnotationScanner.java:127)
	at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.generateAnnotationModel(SmallRyeOpenApiProcessor.java:819)
	at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.build(SmallRyeOpenApiProcessor.java:676)
	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:925)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	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:330)
	at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:252)
	at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:60)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:95)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:485)
	at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:68)
	at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:142)
	at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:97)
	at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:132)
	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.smallrye.openapi.deployment.SmallRyeOpenApiProcessor#build threw an exception: java.lang.IllegalArgumentException: Not a parameterized type!
	at org.jboss.jandex.Type.asParameterizedType(Type.java:228)
	at io.smallrye.openapi.runtime.util.TypeUtil.unwrapType(TypeUtil.java:521)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.isVoidResponse(AnnotationScanner.java:502)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.getDefaultStatus(AnnotationScanner.java:476)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.createResponseFromRestMethod(AnnotationScanner.java:403)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.processResponse(AnnotationScanner.java:360)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceMethod(JaxRsAnnotationScanner.java:443)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.lambda$processResourceMethods$0(JaxRsAnnotationScanner.java:279)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceMethods(JaxRsAnnotationScanner.java:277)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceClass(JaxRsAnnotationScanner.java:247)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceClasses(JaxRsAnnotationScanner.java:222)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.scan(JaxRsAnnotationScanner.java:154)
	at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.scan(OpenApiAnnotationScanner.java:127)
	at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.generateAnnotationModel(SmallRyeOpenApiProcessor.java:819)
	at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.build(SmallRyeOpenApiProcessor.java:676)
	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:925)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	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:116)
	at io.quarkus.builder.BuildExecutionBuilder.execute(BuildExecutionBuilder.java:79)
	at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:157)
	at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:328)
	... 9 more
Caused by: java.lang.IllegalArgumentException: Not a parameterized type!
	at org.jboss.jandex.Type.asParameterizedType(Type.java:228)
	at io.smallrye.openapi.runtime.util.TypeUtil.unwrapType(TypeUtil.java:521)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.isVoidResponse(AnnotationScanner.java:502)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.getDefaultStatus(AnnotationScanner.java:476)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.createResponseFromRestMethod(AnnotationScanner.java:403)
	at io.smallrye.openapi.runtime.scanner.spi.AnnotationScanner.processResponse(AnnotationScanner.java:360)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceMethod(JaxRsAnnotationScanner.java:443)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.lambda$processResourceMethods$0(JaxRsAnnotationScanner.java:279)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceMethods(JaxRsAnnotationScanner.java:277)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceClass(JaxRsAnnotationScanner.java:247)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.processResourceClasses(JaxRsAnnotationScanner.java:222)
	at io.smallrye.openapi.jaxrs.JaxRsAnnotationScanner.scan(JaxRsAnnotationScanner.java:154)
	at io.smallrye.openapi.runtime.scanner.OpenApiAnnotationScanner.scan(OpenApiAnnotationScanner.java:127)
	at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.generateAnnotationModel(SmallRyeOpenApiProcessor.java:819)
	at io.quarkus.smallrye.openapi.deployment.SmallRyeOpenApiProcessor.build(SmallRyeOpenApiProcessor.java:676)
	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:925)
	at io.quarkus.builder.BuildContext.run(BuildContext.java:277)
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	at java.base/java.lang.Thread.run(Thread.java:833)
	at org.jboss.threads.JBossThread.run(JBossThread.java:501)

How to Reproduce?

No response

Output of uname -a or ver

Windows 11

Output of java -version

17.0.2

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.9.1.Final

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

No response

Additional information

No response

@doublefx doublefx added the kind/bug Something isn't working label Jun 7, 2022
@quarkus-bot
Copy link

quarkus-bot bot commented Jun 7, 2022

@geoand
Copy link
Contributor

geoand commented Jun 9, 2022

cc @Sgitario

@Sgitario
Copy link
Contributor

Sgitario commented Jun 9, 2022

Dealing with parameterized types is a bit complex to do, though It's not technically impossible (see some examples).

There is one open issue that will ease the generation of methods that return parameterized types: quarkusio/gizmo#70

Therefore, taking into account that this module is generating many methods, I would be in favor of adding the annotation @APIResponseSchema into the resource method instead, so open API can determine the actual return type and hence solve this issue. Wdyt?

@geoand
Copy link
Contributor

geoand commented Jun 9, 2022

is a bit complex to do, though It's not technically impossible (see some examples).

exactly what I had in mind

I would be in favor of adding the annotation @APIResponseSchema into the resource method instead, so open API can determine the actual return type and hence solve this issue

we could do that, I don't mind

@Sgitario
Copy link
Contributor

Sgitario commented Jun 9, 2022

Unfortunately, adding the annotation @APIResponseSchema didn't solve this issue as Smallrye Open API still tries to determine the return type. I will also add the annotations @APIResponses to workaround this issue, but I think the final solution should be addressed in the Smallrye Open API implementation.

@MikeEdgar
Copy link
Contributor

@Sgitario is the expectation that Smallrye OpenAPI treat a raw Uni as an Object and move on to use @APIResponse* annotations?

@Sgitario
Copy link
Contributor

@Sgitario is the expectation that Smallrye OpenAPI treat a raw Uni as an Object and move on to use @APIResponse* annotations?

I would simply handle the case when a wrapper type is not a parameterized type ("Type.Kind.ParameterizedType").

Moreover, if the method is annotated with @APIResponseSchema, then I would use this type, not the one from method.returnType().

@Sgitario
Copy link
Contributor

Sgitario commented Jun 10, 2022

In addition to my previous comment, I think there is an issue in this line: https://github.com/smallrye/smallrye-open-api/blob/bce528abb3bfad9521524eb3d5d66e1cd8805e7c/core/src/main/java/io/smallrye/openapi/runtime/scanner/spi/AnnotationScanner.java#L366

According to comment, it should only pass when the annotation @APIResponses is not present or is present with no nested @APIResponse annotation.

However, when I annotated my method with @APIResponses(value = [@APIResponse(responseCode = "200")]), it goes in that way.

If the comment is correct, the right logic should be:

if (apiResponses == null || JandexUtil.isEmpty(apiResponses)) { // I removed the exclamation

Wdyt?

@doublefx
Copy link
Author

Looks nice, can't wait at testing it, thanks for your reactivity guys!!

Sgitario added a commit to Sgitario/quarkus that referenced this issue Jun 13, 2022
This pull request will generate the rest data methods using the method signature that allows to use parameterized types. 

Fix quarkusio#25990
@quarkus-bot quarkus-bot bot added this to the 2.11 - main milestone Jun 13, 2022
tmihalac pushed a commit to tmihalac/quarkus that referenced this issue Jun 13, 2022
This pull request will generate the rest data methods using the method signature that allows to use parameterized types. 

Fix quarkusio#25990
@gsmet gsmet modified the milestones: 2.11 - main, 2.10.0.Final Jun 13, 2022
gsmet pushed a commit to gsmet/quarkus that referenced this issue Jun 13, 2022
This pull request will generate the rest data methods using the method signature that allows to use parameterized types.

Fix quarkusio#25990

(cherry picked from commit ddc36e2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/openapi area/smallrye env/windows Impacts Windows machines kind/bug Something isn't working
Projects
None yet
5 participants