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?
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
}
}
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.
What you want is
#Path("/app")
public class YourHandler {
#Path('/')
#Produces(MediaType.APPLICATION_JSON)
public String yourHandlerForApp() {
// Whatever...
}
#Path('/fizz') // <--- right here, will FizzResource live at /app/fizz?
#Produces(MediaType.APPLICATION_JSON)
public String yourHandlerForAppSlashFizz() {
// Whatever...
}
}
Related
I have a REST service with version v1 running fine in production. Now I need to make version v2 url as the response format is changed so we don't want to affect our current customers who are using v1 url. We will be returning some other object back with version v2 url instead of using ClientResponse object.
Below is my current design in which version is provided in #Path annotation. This was done by somebody else who left our team.
#Component
#Scope("request")
#Path("/abc/hello/v1")
public class ClientService {
// ... some variables
#GET
#Path("/json/line")
#Produces(MediaType.APPLICATION_JSON)
public ClientResponse getLineData(#Context UriInfo uriInfo) {
}
}
What is the best way to design version v2 url here? Should I just make a new class and have #Path as #Path("/abc/hello/v2") like this and copy paste everything in it? Or should I create some abstract class and have ClientServiceV1 extend that abstract class and then have ClientServiceV2 extend that abstract class as well? How should I proceed?
My strategy for versioning REST API is to not let JAX-RS runtime automatically determine what REST resources to load and instead explicitly state them in the java.ws.rs.Application implementation.
My java.ws.rs.Application implementation is where I do the versioning and I state it there the base API URI
#javax.ws.rs.ApplicationPath("v1")
public class MyAppV1 extends java.ws.rs.Application {
Set<Class<?>> getClasses() {
return new java.util.HashSet<>(java.util.Arrays.asList(
ClientService.class,
OtherService.class));
}
}
And then create another one for "v2" where I start adding my components there.
The intent of it is I can have multiple versions present and I can deprecate the old ones and eventually remove them as needed. It also allows me to reuse the existing services.
However, if your existing services are suffixed with "v1" then you may want to either duplicate the code or make it point to the new version depending on your needs.
I have several APIs which retain a parameter "feature" from the url (path param). To avoid retrieving it in each method endpoint (eg.)
#GET
public void findAll(#PathParam("feature") String feature);
am trying to implement AOP using AspectJ.
Following is the implementation of the Aspect
#Aspect
public class FeatureAOP {
#Pointcut("execution(* x.y.z.rest.ModifiersFacadeWrapper.*(..)) && args(feature)")
public void pointCut(String feature) {
}
#Before("x.y.z.rest.aop.FeatureAOP.pointCut(feature)")
public void parseParams(JoinPoint jp, String feature) {
Object[] x = jp.getArgs();
System.out.println("Feature: " + feature);
}
}
The above method gives me the value of "feature" in the Aspect class but if I change the method findAll to following signature, it doesn't works.
#GET
public void findAll();
What I understand is the control is transferred to the Aspect after the parameters are resolved and removing it from the method definition is failing it.
Doing so, thus takes me to the same point where I have to define all method endpoints with the parameter in its signature. I would like to know if there is a way I can get the PathParams in the Aspect class without having to define my methods with the designated parameters.
I think you could probably do it by putting the resolved params in a globally accessible data structure (e.g. a Singleton having some sort of Map or Set), but
I wouldn't recommend that kind of approach. I don't know why you don't like having all the params in your method signatures, but that is the intended way of declaring rest services, e.g.
#GET
#Path("{feature}")
#Produces("text/plain")
public String getFeature(#PathParam("feature") String feature) {
return feature;
}
This way you don't have to write any code for retrieving the params, the rest library you are using (be it Jersey or a different one) will just do everything for you.
Suppose Animal is an abstract class in my project, and I have a REST resource (on a JAX-RS server, using Jackson for (de)serialization) for a PUT to manipulate animals that are stored in my database. They have concrete types, and the REST resource specifies the type in the path of the request:
#PUT
#Consumes(MediaType.APPLICATION_JSON)
#Path("/{entityType}/{id: \\d+}")
public <T extends Animal> void putAnimal(#PathParam("entityType") String entityType, #PathParam("id") String id, Animal input) throws IOException {
//...
}
I want to use entityType to pick the concrete class to deserialize with (Dog or Cat or whatever, for entityType being dog or cat or whatever). For reasons which are too complicated to explain here, I cannot put the type information in the JSON input itself.
So AIUI annotating Animal with a custom TypeIdResolver or something of the sort can't help me, because the type information won't be in the JSON itself (and that's all the info that the type resolver will get). I was planning to use a custom MessageBodyReader, but as far as I can tell, that doesn't get the other parameter values from the body passed in its readValue method, so I won't know what to deserialize into.
What am I missing? If this approach fails, how can I accomplish what I want without specifying animal-specific endpoints (which leads to lots of duplicate code as well as a loss of generality - right now I can add an subclass of Animal and this code will Just Work, which is very nice.)
The below quote from the JAX-RS specification (5.2.2 URIs and URI Templates) suggests that you should be able to inject a UriInfo instance into your custom MessageBodyReader, and use one of its methods to inspect the URL path of the request.
An instance of UriInfo can be injected into a class field or method parameter using the #Context an- notation. UriInfo provides both static and dynamic, per-request information, about the components of a request URI.
The example provided there shows a resource method receiving a UriInfo parameter, but normally it should be possible to inject an instance to a provider (MessageBodyReader) as well.
After obtaining the entityType path param through the UriInfo, your MessageBodyReader should be able to provide the corresponding sublclass of Animal.
Given what you are trying to do you are better off building an AnimalResource class which contains your basic methods and then building separate DogResource, CatResource and whatever other classes you need which extend AnimalResource. This will allow you to obtain the correct subclass of Animal and so deserialize the input JSON correctly.
Update
An example of how this might be achieved. Your base resource looks something like this:
public class AnimalResource<T extends Animal>
{
private final transient AnimalService<T> service;
public AnimalResource(final AnimalService<T> service)
{
this.service = service;
}
#Get
#Path("{id}")
#Produces(MediaType.APPLICATION_JSON)
public T getbyId(#PathParam("id") final String id)
{
return this.service.findById(id);
}
// Other CRUD methods go here
}
And then your individual animals, assuming that they all have the same setup, are simply:
#Path("/cats")
public class CatResource extends AnimalResource<Cat>
{
public CatResource(final CatService catService)
{
super(catService);
}
}
for a cat and
#Path("/dogs")
public class DogResource extends AnimalResource<Dog>
{
public DogResource(final DogService dogService)
{
super(dogService);
}
}
for a dog. They will inherit the standard CRUD methods from the parent, and any animal-specific methods can still go in the individual *Resource class.
Using Jersey, what is the RESTish way to this, Should I create a method starting with "update" like this, or I should create a subresource (or whatever Jax-Rs thing) under accountseetings path? Or should I simply use the same method name with different verbs?
#GET
#Path("/accountsettings")
public Settings accountSettings() {
}
#PUT
#Path("/updateaccountsettings")
public void updateAccountSettings() {
}
In REST verbs define what you are doing and URLs define what you are doing it to.
So here a PUT to /accountsettings would seem to be the normal way to do it.
Calling the method updateAccountSettings() seems to make sense.
I have a class this is annotated with #Path like so:
#Path("widgets")
#Produces(MediaType.APPLICATION_XML)
public class WidgetResource {
#GET
public Response getWidgets(#QueryParam("limit"))
{
//This class returns the plural noun, a list of widgets
//...}
#GET
#Path("widget/{id}")
public Response getWidgetById(#PathParam("id") long id)
{
//This class returns a single widget by id
//...}
When I fire up a test client the localhost/widgets maps as expected, but when the getWidgetById method is mapped to localhost/widgets/widget/{id}. This is not what I want - I would like to have localhost/widgets and localhost/widget/{id}
I have tried omitting the #Path annotation at the class level, but that prevents Jersey from recognizing this class as a REST Resource (I tried both the ScanningResourceConfig and the ClassNameResourceConfig - both failed to load the class as a resource unless there was a #Path at the class level).
I guess a (ugly) workaround would be to split the methods between classes a WidgetResource class and a WidgetsResource class. I think this is a terrible solution since both of these methods share resources in the same class, but I really need the REST-ful localhost/widget (for a single entity) and localhost/widgets (for plural).
Am I missing something - is there some way for me to have Jersey pick up the class as a Resource class if I just #Path annotate the methods (I couldn't get it to work), if not can I force absolute mapping (#Path(/widget/{id})) or some relative mapping (#Path(../widget/id) - neither of those work in reality - just an analogy of what I'm after. Thanks!
This part is about what you need:
Personally, I find your mapping strange and confusing. Just keep it like this:
#Path("widgets")
#Produces(MediaType.APPLICATION_XML)
public class WidgetResource {
#GET
public Response getWidgets(#QueryParam("limit")) {
//This method returns the plural noun, a list of widgets
// it's also possible to limit the number returned by
// using a query parameter. You could easily implement
// pagination by adding further query parameters like
// 'offset', 'sortOrder', etc.
//...
}
#GET
#Path("{id}")
public Response getWidgetById(#PathParam("id") long id) {
//This method returns a single widget by id
//...
}
}
It seems natural to append the path to a collection with an ID to fetch an object from the collection. There's really no need to make it widgets/widget/{id}. The widget part is obvious and unnecessary.
Here's a really neat tutorial on RESTful APIs: "Teach a dog to REST" by apigee I think it's a really good video. The authors make a couple of good points. And here's a link to a longer version of the same presentation
This part is about what you want:
If you really want to keep the plural/singular dualism (which I really don't recomment), you can annotate your code like this:
But it's really ugly
#Path("/")
#Produces(MediaType.APPLICATION_XML)
public class WidgetResource {
#GET
#Path("widgets")
public Response getWidgets(#QueryParam("limit")) {
//This method returns the plural noun, a list of widgets
//...}
#GET
#Path("widget/{id}")
public Response getWidgetById(#PathParam("id") long id) {
//This method returns a single widget by id
//...
}
}
My suggestion is to have your paths be:
"widgets" and "widgets/id/{id}". Or if you knew you were never going to query by anything other than id, your second one could simply be "widgets/{id}".
I would not switch between plural and singular in your path. Since you accessing the same type of resource for both, your root should be the same. The second form just specifies it more -- a vectoring-based approach for getting more specific.