Describe the bug
If your REST resource extends an abstract base class that contains all the typical annotations like @Path, @GET etc. then you'll see this failure when invoking the resource:
2020-10-25 23:39:01,178 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-1) HTTP Request to /hello failed, error id: fb45d7cc-5fa1-4aa5-ae5c-fa458d3b702d-1: org.jboss.resteasy.spi.UnhandledException: java.lang.RuntimeException: java.lang.InstantiationException
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:381)
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:131)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:37)
at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:94)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at java.base/java.lang.Thread.run(Thread.java:834)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Caused by: java.lang.RuntimeException: java.lang.InstantiationException
at io.quarkus.arc.runtime.BeanContainerImpl$DefaultInstanceFactory.create(BeanContainerImpl.java:75)
at io.quarkus.resteasy.common.runtime.QuarkusConstructorInjector.construct(QuarkusConstructorInjector.java:54)
at org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory.createResource(POJOResourceFactory.java:71)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:386)
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:68)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
... 17 more
Caused by: java.lang.InstantiationException
at java.base/jdk.internal.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:48)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at java.base/java.lang.Class.newInstance(Class.java:584)
at io.quarkus.arc.runtime.BeanContainerImpl$DefaultInstanceFactory.create(BeanContainerImpl.java:67)
... 22 more
Such abstract base classes can be the result of https://github.com/OpenAPITools/openapi-generator
Expected behavior
Resource classes can use abstract base classes (that contain JAX-RS annotations) without problems.
Actual behavior
Invocation of such a resource fails.
To Reproduce
Steps to reproduce the behavior:
git clone https://github.com/famod/quarkus-quickstartsgit switch rest-abstractcd getting-startedmvn clean verify (will fail with the mentioned error)mvn clean package -DskipTestsjava -jar target/getting-started-1.0-SNAPSHOT-runner.jarcurl localhost:8080/hello (will fail with the mentioned error)Configuration
not relevant
Environment (please complete the following information):
uname -a or ver: MINGW64_NT-10.0-18363 XXX 3.0.7-338.x86_64 2019-11-21 23:07 UTC x86_64 Msysjava -version: OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.8+10, mixed mode)mvnw --version or gradlew --version): Apache Maven 3.6.3Additional context
Interfaces do work but annotation discovery has some blind spots in that case:
/cc @patriot1burke @gsmet
hmm, this will work for interfaces, but the spec does not require it to work this way for abstract classes.
@stuartwdouglas
but the spec does not require it to work this way for abstract classes
Well, I found this: https://stackoverflow.com/a/25924310/9529981
To resolve quoted quoting:
3.6 Annotation Inheritance
JAX-RS annotations may be used on the methods and method parameters of a super-class or an implemented interface. Such annotations are inherited by a corresponding sub-class or implementation class method provided that the method and its parameters do not have any JAX-RS annotations of their own. Annotationson a super-class take precedence over those on an implemented interface. The precedence over conflicting annotations defined in multiple implemented interfaces is implementation specific. Note that inheritance ofclass or interface annotations is not supported. If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored
see https://download.oracle.com/otn-pub/jcp/jaxrs-2_0-fr-eval-spec/jsr339-jaxrs-2.0-final-spec.pdf
May I kindly ask you @asoldano for an opinion from the RESTeasy POV?
This is supposed to work. Quarkus is probably adding the abstract class as a resource by mistake.
Can you post a simplified example of what triggers the problem? I want to make sure I'm testing all the scenarios.
Can you post a simplified example of what triggers the problem?
Even simpler than what I described under "To Reproduce"? No, sorry, not at the moment.
Or do you mean something closer to what we are using in our internal project (that is: openapi generated classes)?
Apologies!!! I need to learn to read. :)
No worries, it happens to all of us! 馃榿
Pretty sure this is the issue:
" Note that inheritance of class or interface annotations is not supported."
Concrete classes must specify a @Path annotation at the class level. (FYI, I was on JAX-RS 2.0 spec).
@Path("/foo")
public class Concrete extends MyAbstract {
}
Quarkus is spitting out the wrong error message, but this wouldn't be supported in Resteasy anyways.
FYI, the reason for requiring @Path on the concrete class is for cases where multiple classes extended the same abstract class (or interface), IIRC.
Interesting! I can confirm that moving @Path from the abstract class to the concrete class fixes the problem.
Additionally, a method level @Path annotation in the abstract class is (still) picked up correctly.
But why is a "class level" @Path working if defined in an _interface_ instead of an abstract class?
I mean, it is good that it's working this way because that's what openapi generator is spitting out (when using interface mode).
Otherwise we would have to annotate each and every of our concrete resource classes.
PS: All this also means that openapi-generator producing class level @Path in abstract classes is pointless and misleading.
I am not saying openapi generator is free of problems/bugs but it's all a bit confusing.
Nevermind, looks like Resteasy supports that case too. Sorry, its been so long since I've had to deal with this (10years). Patch incoming.