In my current architecture, I have a JAX-RS resource that sits behind:
/categories
/categories/{catId}
that's implemented like this:
@Path("/categories")
@Produces("application/json")
public class CategoryResourcesApi {
@GET
public Response getCategories() {
// ...
}
@GET @Path("/{catId}")
public Response getCategory(@PathParam("catId") String catId) {
// ...
}
// ...
}
and another one that serves:
/products
/products/{prodId}
and has a similar implementation:
@Path("/products")
@Produces("application/json")
public class ProductResourcesApi {
@GET
public Response getProducts() {
// ...
}
// ...
}
Apart from these straightforward paths, I also need to serve these:
/categories/{catId}/products
/categories/{catId}/products/{prodId}
which would be products related to a specific category.
The most natural thing to do would be make ProductResourcesApi
serve them, but by the way I understand the JAX-RS annotations structure, this can only be served by CategoryResourcesApi
(or eventually by a third class, I think).
I'm using @Context
and other annotations in my resource implementations, so a direct new ProductResourcesAPI().getProducts()
wouldn't work, I guess.
Is there any way to forward from one resource path to another within the JAX-RS (or Jersey) framework? What other options do I have? I'd like to keep all this easily maintainable if possible, that's why I chose one resource for each root path with subresources within.
For this you can use Sub-resource locators, which is basically a method in the resource class that returns another resource class. The thing about the examples in the link is that they instantiate the resource class themselves, for example
which works, but I am not sure if it preserves injections, for instance if you wanted to inject
@Context UriInfo
into a field inItemContentResource
. It should work though if you injected into the method param instead.To get around this, there is the
ResourceContext
, which when used, should preserve all the injections. For example in your current case, you can doThe
getProducts
would map to the URI/categories/{catId}/products/{prodId}
. You just need to check if thecatId
is null (only if you need it to do any lookup) I guess to determine if the request is a request to the root products resource or to the parent categories resource. Small price to pay for code reuse I guess.And just looking at your comment, I believe in the past Swagger didn't support sub-resource locators, but I believe now they do. You may want to search around for any discussions if you have problems with it. Here's a discussion, and another one, and another one