Quarkus: RESTEasy tries to instantiate abstract resource base class

Created on 25 Oct 2020  路  14Comments  路  Source: quarkusio/quarkus

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:

  1. git clone https://github.com/famod/quarkus-quickstarts
  2. git switch rest-abstract
  3. cd getting-started
  4. mvn clean verify (will fail with the mentioned error)
  5. mvn clean package -DskipTests
  6. java -jar target/getting-started-1.0-SNAPSHOT-runner.jar
  7. curl localhost:8080/hello (will fail with the mentioned error)

Configuration
not relevant

Environment (please complete the following information):

  • Output of uname -a or ver: MINGW64_NT-10.0-18363 XXX 3.0.7-338.x86_64 2019-11-21 23:07 UTC x86_64 Msys
  • Output of java -version: OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.8+10, mixed mode)
  • GraalVM version (if different from Java): n/a
  • Quarkus version or git rev: 1.9.0.Final
  • Build tool (ie. output of mvnw --version or gradlew --version): Apache Maven 3.6.3

Additional context
Interfaces do work but annotation discovery has some blind spots in that case:

areresteasy kinbug

All 14 comments

/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.

Was this page helpful?
0 / 5 - 0 ratings