Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Will JAX-RS/Jersey resource paths honor inheritance?

Say I want the following URLs exposed by my JAX-RS/Jersey app:

http://myapp.example.com/app/fizz
http://myapp.example.com/app/buzz
http://myapp.example.com/app/foo
http://myapp.example.com/app/bar

Say I want /app to be a parent base resource, and /app/* to be "child" resources. Will the following accomplish the URL strategy I'm looking for (?):

@Path('/app')
@Produces(MediaType.APPLICATION_JSON)
public abstract class AppResource {
    // Whatever...
}

@Path('/fizz') // <--- right here, will FizzResource live at /app/fizz?
@Produces(MediaType.APPLICATION_JSON)
public class FizzResource extends AppResource {
    // Whatever...
}

Will the FizzResource be exposed at /app/fizz or just /fizz?

like image 651
smeeb Avatar asked Nov 13 '15 13:11

smeeb


2 Answers

Will the FizzResource be exposed at /app/fizz or just /fizz?

Short answer

FizzResource will be exposed at /fizz.

Long answer

Quoting the JSR 339 (section 3.6 about Annotation Inheritance):

If a subclass or implementation method has any JAX-RS annotations then all of the annotations on the superclass or interface method are ignored.

The specification also says:

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

Creating sub-resources

The JAX-RS/Jersey documentation explains how to create sub-resources:

@Path may be used on classes and such classes are referred to as root resource classes.

@Path may also be used on methods of root resource classes. This enables common functionality for a number of resources to be grouped together and potentially reused.

The first way @Path may be used is on resource methods and such methods are referred to as sub-resource methods.

So, do the following to create sub-resources:

@Path("/app")
public class YourHandler {

    @Produces(MediaType.APPLICATION_JSON)
    public String yourHandlerForApp() {
        // This method is be exposed at /app
    }

    @Path("/fizz") 
    @Produces(MediaType.APPLICATION_JSON)
    public String yourHandlerForAppSlashFizz() {
        // This method is be exposed at /app/fizz
    }
}
like image 54
cassiomolin Avatar answered Nov 16 '22 22:11

cassiomolin


I don't think the answers given are the best for the original problem statement.

He wants to have his subresources in separate classes. That's understandable and admirable because to not do that would mean putting all his endpoints in the same class, which would be huge.

If all endpoints on this port start with /app then I think the best way to do that is to configure your filter to put it in your @ApplicationPath.

If it's not the case that all endpoints start with the same prefix, then you will have to use this style of JAX-RS subresources where you specify a @Path but not an HTTP method annotation (@GET, etc.) and return an instance of the resource you want to delegate to:

@Path("/app")
public class AppResource {
    @Context UriInfo uriInfo;

    @Path("fizz")
    public FizzResource getItemContentResource() {
        return new FizzResource ();
    }
}

@Produces(MediaType.APPLICATION_JSON)
public class FizzResource extends AppResource {
    // Whatever...
}

This method of doing resources is provided in the JAX-RS documentation.

You can also have all your subresources declare their Paths as

    @Path(BASE_URL + "/fizz")

Where BASE_URL is a static string, but I would try to avoid that because the use of a not-exactly constant parameter to @Path seems to cause every JAX-RS IDE plugin I've seen problems. They aren't able to compute the actual path, so they give up. So you might lose the ability to have a "JAX-RS View" that allows you to visualize/navigate your JAX-RS resources by the Paths.

like image 37
DaBlick Avatar answered Nov 16 '22 21:11

DaBlick