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

Bug Report: Implementing JAX-RS resources using Generated Interfaces #5553

Closed
mhlulani opened this issue Jan 9, 2022 · 7 comments
Closed
Assignees
Labels
Type: Bug Label issue as a bug defect

Comments

@mhlulani
Copy link

mhlulani commented Jan 9, 2022

Description


I'm using a maven-plugin (options) to generate only interfaces (along with models) and in turn implement those interfaces when creating a new JAX-RS resource. The generated code is a separate Maven project (JAR) which is simply referenced as a dependency in my microservice project.

This works on Wildfly but on Payara (MicroProfile) it identifies on the endpoints/resources correctly,

[2022-01-09T06:37:43.979+0200] [] [INFO] [] [PayaraMicro] [tid: _ThreadID=1 _ThreadName=main] [timeMillis: 1641703063979] [levelValue: 800] [[
  
Payara Micro URLs:
http://192.168.0.103:8080/

'ROOT' REST Endpoints:
GET	/openapi/
GET	/openapi/application.wadl
GET	/v2/application.wadl
GET	/v2/metric/increment
GET	/v2/metric/timed
GET	/v2/notifications  <- THIS ONE
POST	/v2/notifications/{id}   <- AND THIS ONE

]]

but fails when you try accessing the resource, it tries to instantiate the interface as apposed to the actual implementation

As a team of developers and other non-developers, this helps bind our services to a specific contract which is defined by the open-api spec (yaml).

Expected Outcome

The concrete implementation should be instantiated because we cannot instantiate an Abstract class or Interface

Current Outcome

When accessing any of these resources with implement an interface we get the following error:

[2022-01-09T06:37:49.988+0200] [] [WARNING] [] [javax.enterprise.web] [tid: _ThreadID=96 _ThreadName=http-thread-pool::http-listener(2)] [timeMillis: 1641703069988] [levelValue: 900] [[
  StandardWrapperValve[com.mtn.madapi.notification.AppConfig]: Servlet.service() for servlet com.mtn.madapi.notification.AppConfig threw exception
java.lang.NoSuchMethodException: Could not find a suitable constructor in com.mtn.madapi.contract.notification.api.NotificationSettingsApi class.
	at org.glassfish.jersey.inject.hk2.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:168)
	at org.jvnet.hk2.internal.Utilities.getConstructor(Utilities.java:156)
	at org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:1042)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.create(ServiceLocatorImpl.java:969)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:1073)
	at org.jvnet.hk2.internal.ServiceLocatorImpl.createAndInitialize(ServiceLocatorImpl.java:1065)
	at org.glassfish.jersey.inject.hk2.AbstractHk2InjectionManager.createAndInitialize(AbstractHk2InjectionManager.java:189)
	at org.glassfish.jersey.inject.hk2.ImmediateHk2InjectionManager.createAndInitialize(ImmediateHk2InjectionManager.java:30)
	at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:106)
	at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:260)
	at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:51)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:86)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:89)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:89)
	at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:89)
	at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:69)
	at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:38)
	at org.glassfish.jersey.process.internal.Stages.process(Stages.java:173)
	at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:245)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
	at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
	at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:232)
	at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680)
	at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394)
	at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:366)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:319)
	at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
	at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1636)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:259)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:757)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:577)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:158)
	at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238)
	at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:520)
	at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:217)
	at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:182)
	at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:156)
	at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:218)
	at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:95)
	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:260)
	at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:177)
	at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:109)
	at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:88)
	at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:53)
	at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:524)
	at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:89)
	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:94)
	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:33)
	at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:114)
	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:569)
	at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:549)
	at java.base/java.lang.Thread.run(Thread.java:829)

Steps to reproduce

You can create a new project using https://start.microprofile.io using the following configurations:
Screenshot from 2022-01-09 07-21-52

@ApplicationPath should not need any modification but MUST be present

import javax.enterprise.context.ApplicationScoped;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath("/v2")
public class JaxRsConfig extends Application {
}

I'm using a generated interface but even just creating one within the same project has the same result:

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/foo")
public interface FooApi {
    @GET
    Response bar(@QueryParam("key") String key) throws Exception;
}

Implement the interface in a concrete class (JAX-RS resource)

import javax.enterprise.context.RequestScoped;
import javax.ws.rs.core.Response;

@RequestScoped
public class FooResource implements FooApi { // <- HERE

    @Override // All JAX-RS annotations are driven by the contract FooApi
    public Response bar(String key) throws Exception {
        return Response
                .ok("Foo Bar " + System.currentTimeMillis())
                .build();
    }
}

Build Service

mvn clean install

Run Service

java -jar target/foo-api-2.0.0-SNAPSHOT-microbundle.jar

Sending requests:

curl "http://localhost:8080/v2/foo"

Environment

  • Distribution: Micro
  • JDK Version: 11
  • Operating System: Linux
@mhlulani mhlulani added Status: Open Issue has been triaged by the front-line engineers and is being worked on verification Type: Bug Label issue as a bug defect labels Jan 9, 2022
@mhlulani
Copy link
Author

mhlulani commented Jan 9, 2022

This works on Wildfly/JBoss

@shub8968 shub8968 self-assigned this Jan 10, 2022
@shub8968
Copy link
Contributor

shub8968 commented Jan 10, 2022

Hi @mhlulani,

Kindly refer to - #3944 (comment) / #3944 (comment). These already address your issue. But you can raise an Enhancement Request describing your concern.

@shub8968 shub8968 added Status: Pending Waiting on the issue requester to give more details or share a reproducer and removed Status: Open Issue has been triaged by the front-line engineers and is being worked on verification labels Jan 10, 2022
@hlulani-eoh
Copy link

I see, this is such a shame https://jakarta.ee/specifications/restful-ws/3.0/jakarta-restful-ws-spec-3.0.html#annotationinheritance

My whole project was based on this solution

@hlulani-eoh
Copy link

@shub8968

@rdebusscher
Copy link

Hi,

The specification mention that annotations should only be on methods of the inherited interface, not the interface itself. (first sentence of the link to the spec you made)

JAX-RS annotations may be used on the methods and method parameters of a super-class or an implemented interface.

In your example, you have a @path on the interface class definition itself which triggers Jersey, the JAX-RS implementation to indicate the interface isn't a valid JAX-RS resource (as according to the spec).

But besides the Stacktrace, the endpoint should be usable although it is not as defined by the specification.

Best Regards
Rudy

@fturizo fturizo added Status: Open Issue has been triaged by the front-line engineers and is being worked on verification and removed Status: Pending Waiting on the issue requester to give more details or share a reproducer labels Jan 11, 2022
@fturizo
Copy link
Contributor

fturizo commented Jan 13, 2022

@hlulani-eoh, as @rdebusscher stated, the behaviour that you have reported is not an issue of Payara Server, since @Path annotated interfaces can't be used to instantiate JAX-RS resource class. The issue that you referenced, #3944, has already been reported and fixed in the main Jersey repository on this issue: eclipse-ee4j/jersey#4847, and will be integrated on Payara Server when we integrate this new release of Jersey.

We'll proceed to close this issue since there's nothing to fix at the moment.

@fturizo fturizo closed this as completed Jan 13, 2022
@fturizo fturizo removed the Status: Open Issue has been triaged by the front-line engineers and is being worked on verification label Jan 13, 2022
@hlulani-eoh
Copy link

@fturizo Thank you,
I'll wait for the new updates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Type: Bug Label issue as a bug defect
Projects
None yet
Development

No branches or pull requests

5 participants