23

I don't know if the title is confusing, but let's say I have this interface:

@Produces(MediaType.APPLICATION_JSON)
@Path("/user")
public interface UserService {

    @GET
    @Path("/{userId}")
    public Response getUser(@PathParam("userId") Long userId);

}

Why when I try to implement a version Eclipse rewrites annotation for the overridden method but not for the class?

class UserServiceImpl implements UserService {

    @Override
    @GET
    @Path("/{userId}")
    public Response getUser(@PathParam("userId") Long userId) {
        // TODO Auto-generated method stub
        return null;
    }

}

I was trying to create a standard definition for the restful web service and then having different implementations. Is something like this possible with standard jax-rs? Am I using wrong annotations by any chance?

Cœur
  • 37,241
  • 25
  • 195
  • 267
dierre
  • 7,140
  • 12
  • 75
  • 120

2 Answers2

29

You can use annotation inheritance only if you don't use any jax-rs annotation on the implementing class: it is stated on section 3.6 of JSR-339.

You redefine @Path and @Produces for the method but not for the class.

So the Path annotation in your code should be on the concrete class:

public interface UserService {

    @GET
    @Path("/{userId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getUser(@PathParam("userId") Long userId);

}


@Path("/user")
class UserServiceImpl implements UserService {

    @Override
    @GET
    @Path("/{userId}")
    @Produces(MediaType.APPLICATION_JSON)
    public Response getUser(@PathParam("userId") Long userId) {
        // TODO Auto-generated method stub
        return null;
    }

}

BTW, the specification encourages us to replicate the annotations on the concrete classes:

For consistency with other Java EE specifications, it is recommended to always repeat annotations instead of relying on annotation inheritance.

Carlo Pellegrini
  • 5,656
  • 40
  • 45
  • 1
    you actually do not need to put the annotations both on interface and the concrete. you can just put all on the interface except for the @Path on the class (@Path("/user")). – shlomi33 Mar 04 '15 at 12:23
  • 3
    i meant that you can leave it on the interface no the concrete. this way you can make the interface available for a client proxy. – shlomi33 Mar 04 '15 at 13:57
  • @shlomi33 You are right, but it is not an encouraged practice. Maybe after the last edit it is better stated. – Carlo Pellegrini Mar 04 '15 at 15:49
  • I have found that if I add POST and PathParam on interface method but not on implementing class method, I get 404. (Using jersey, grizzly). – Shafiul Aug 07 '16 at 05:02
  • 2
    The quote mentioned in this answer can be found in 3.6 Annotation Inheritance in this doc(pdf): http://download.oracle.com/otn-pub/jcp/jaxrs-2_0-edr2-spec/jaxrs-2_0-edr2-spec.pdf – krock Apr 20 '17 at 22:55
  • @CarloPellegrini Your recommendation of writing the annotations on both the interface and implementation classes violates the [DRY principle](https://en.wikipedia.org/wiki/Don't_repeat_yourself). I am curious as to where your recommendation comes from. Could you provide a source? – Jonathan Komar Jul 08 '20 at 11:41
3

I had a similar issue working with interface automatically generated using the OpenAPI generator. The problem here was that I couldn't easily remove the @Path annotation from the interface and additionally adding it to the class caused ambiguity issues.

Problems with @Path-annotated interfaces however only occurs for resources that are automatically discovered on registered packages. For registered packages, all classes (and unfortunately interfaces as well) that are annotated with @Path will be instantiated.

To prevent that, you can just register your resources manually with your ResourceConfig as in the following example:

new ResourceConfig()
    .registerClasses(UserServiceImpl.class);

Just make sure, your interfaces are not in a package that are registered with your ResourceConfig. Using this approach, you can use the implementation from your example and also the @Path annotation added to the interface will be interpreted correctly.

Disclaimer: There probably should not be any @Path path annotation on the interface in the first place, but unfortunately this is what the OpenAPI generator creates. If you find yourself in a similar situation, I hope this helps. Otherwise, you should refer to the accepted answer.

Jan Gassen
  • 3,406
  • 2
  • 26
  • 44