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

@Path annotation not used if inherited from an interface #262

Open
michael-schnell opened this issue Mar 28, 2020 · 10 comments
Open

@Path annotation not used if inherited from an interface #262

michael-schnell opened this issue Mar 28, 2020 · 10 comments
Labels
Milestone

Comments

@michael-schnell
Copy link

The @Path annotation is not used if it is inherited from an interface.

Example for a base interface:

@Path("/persons")
public interface PersonResource {
}

The client interface now inherits from the above one:

@RegisterRestClient(configKey = "person-service")
public interface PersonService extends PersonResource {
}

This will lead to the following (wrong) call:

http://localhost:8080/whatever

Adding a superfluous @Path on the rest client interface makes it work correctly:

@Path("/persons")
@RegisterRestClient(configKey = "person-service")
public interface PersonService extends PersonResource {
}

This will lead to the following (correct) call:

http://localhost:8080/persons/whatever

The expected behaviour would be, that the @Path annotation is correctly used from the parent interface and there is no need to duplicate it.

@andymc12
Copy link
Contributor

andymc12 commented Mar 28, 2020

Hi @michael-schnell , thanks for opening this issue. We try to follow JAX-RS's lead where possible, and in section 3.6 of the JAX-RS Spec, it talks about annotation inheritance - specifically:

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. Annotations on 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 of class or interface annotations is not supported.

So for MP Rest Client, implementations should support annotation inheritance on methods, but not on interfaces.

That said, I don't see that this is documented in the MP Rest Client specification - and I don't think there are any TCK tests for this. So, if you don't mind, I'd like to keep this issue open to clarify this behavior in the spec/TCK.

Thanks again!

@michael-schnell
Copy link
Author

The feature would be quite handy espcially for the JAXS-RS client part. It allows to keep the client fully aligned with the server, but without putting the @RegisterRestClient annotation on the interface used by the server implementation class.

// JAX-RS server interface 
// Full definition of functionality (including "path")
@Path("/persons")
public interface PersonResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Person> getAll();

}

// JAX-RS client interface
// Used by external parties
@RegisterRestClient(configKey = "person-service")
public interface PersonService extends PersonResource {
}

// JAXS-RS server class  
// Uses the server interface (not the client one!)
public class PersonResourceImpl implements PersonResource {

    @Inject
    EntityManager em;

    @Override
    public List<TenantListEntry> getAll() {
        return em.createNamedQuery(GET_ALL, Personclass).getResultList();
    }

}

Maybe it could be worth to adjust the MP Rest Client specification, because it is a little bit different from what is appropriate for the server side.

@rdebusscher
Copy link
Member

But defining it in the spec would result in a contradiction.

MP Rest client is based on top of JAX-RS where it is defined as it CANNOT inherit class-level annotations. Defining it in MP Rest client that it must inherit result in a conflict for the ALL MP implementations.

They MUST and MUST NOT inherit the class-level annotations on an interface or superclass.

This must be addressed first at the Jakarta Rest specification to make a change.

@michael-schnell
Copy link
Author

You are right. Unfortunately the client works actually "the other way round". The usage is simply slightly different from what is fine for the server. Therefore it would be a good idea to change the specification and clarify the differences between "server side" and "client side".

@Emily-Jiang
Copy link
Member

I am a bit confused on this. The annotation @RegisterRestClient is only applicable on the client side and it should not have or does not make sense to have @Path, which should be on the server side. By the way, there is no class/interface sharing between the client and service.

@michael-schnell
Copy link
Author

You can simply put "PersonService" and "PersonResource" interfaces into a separate "client.jar". This way the client has the necessary information to build it's MP Rest Client instance, but it does not see any implementation code. There is a clean separaration of the layers.

Then you'll have a "server.jar" that depends on "client.jar" and has the "PersonResourceImpl" class that implements "PersonResource" (not "PersonService" which has the @RegisterRestClient annotation).

The main problem with the "client proxy" approach taken by libraries like MP Rest Client is to keep server & client aligned. By sharing the same interface it cannot diverge by accident.

And yes, the "PersonService" should not have the @Path annotation, that is why above interface inheritance is wanted.

@rquinio
Copy link

rquinio commented Oct 7, 2020

I faced the same issue with the Quarkus extension for mp-rest-client (the discovery is done here: https://github.com/quarkusio/quarkus/blob/0d5e73bcb70bbf7b1d102384a01df44e5b3ea1c6/extensions/rest-client/deployment/src/main/java/io/quarkus/restclient/deployment/RestClientProcessor.java#L180-L187)

In a schema-first workflow, the interface for REST client (and server) can be generated from the OpenAPI schema (via a tool like https://github.com/OpenAPITools/openapi-generator ). But today you need to generate differently for a REST client or REST server, the REST client needing this extra @RegisterRestClient annotation that has to be on the same interface as @Path.

@andymc12
Copy link
Contributor

Coming back to this now. I'm not sure what we can do with this in the MP Rest Client, but I wonder if this might be something we could bring the the Jakarta REST folks - to enable class-level path inheritance.

@michael-schnell
Copy link
Author

Sounds good

@CENGOiSM
Copy link

CENGOiSM commented Jan 29, 2021

I am facing the same issues right now.
Searching for a solution I found that annotating @Provider on the implemented class is solving the mentioned problems.
What do you think about this approach, am I missing something?

@Path("/persons")
public interface PersonResource {
}

@Provider
public class PersonResource implements PersonResource {
}

@jclingan jclingan added this to the Future milestone Feb 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants