JAX-RS resource method signatures - java

I'm using Jersey 2.19 to implement a REST API.
I'd like to know how I find out from the Jersey user guide or other specification how I'm supposed to know what the signature of my JAX-RS resource should be.
E.g. for a resource that handles POST requests I've experimented with the following different signatures using examples I've found.
public Response myResource()
public Response myResource(String param)
Both of these are valid in that they compile and run and the method is called under the right conditions.
Can anyone tell me where it is specified what the signatures should be and what the parameters mean? It seems like a straightforward question but I can't find the answer.

As you are saying its a POST request , so it should recieve some data from the Request. So you should expect something in Parameter.
public Response myResource(String param)
But the type of parameter should depend upon actually #Consumes annotation like :-
#Consumes(MediaType.APPLICATION_JSON) : This expects a JSONinput OR
#Consumes(MediaType.APPLICATION_XML) : This expects a XMLinput OR
#Consumes(MediaType.TEXT_PLAIN) : This expects a String plain text input

You annotate your Methods like described in the official documentation.
Also, do not forget to annotate the service-class with #Path
#Path("MyService")
public class MyService
{
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/User")
public List<User> getUser()
{
//Return all users
}
//Inserts new User in JSON Format
#Get
#Path("/User/UserId/{userid}")
public User getUserById(#PathParam("userid") String userid)
{
//Find User with ID in Database and return it
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public User getUserById(User user)
{
//add user to your Database or something
}
}
If you now want to get all users in json format you have to call:
http://ip-address/MyService/user

There is an exact answer to your question, but gird your loins. Because if the Jersey docs are overly vague these are in the extreme opposite direction: written by someone showing off their PhD in abstract algebra it looks to me.
The answer to everything is in the JAX-RS spec, of which Jersey is an implementation. You can download it here as PDF (after you sign away your soul)
The specific answer to how one of those methods is selected instead of the other, is too detailed for me to paste in here, but it's under section "3.7.2 Request Matching"
I won't even try to paste in the mathematical rules used to set up the list of potential methods to match a request, then select from among them. There's no chance of getting them formatted readably in SO.
For your more general questions, the section "3.3 Resource Methods" is much more accessible. Here are a few choice excerpts:
3.3 Resource Methods
...
JAX-RS defines a set of
request method designators for the common HTTP methods: #GET, #POST,
#PUT, #DELETE, #HEAD and #OPTIONS.
...
3.3.1 Visibility: Only public methods may be exposed as resource methods.
...
3.3.2 Parameters: Resource methods MUST have at most one entity parameter ...
3.3.3 Return Type: Resource methods MAY return void, Response, GenericEntity, or another Java type...
etc, etc.

Related

Is there a way to define queryparams for all endpoints in javax.ws.rs?

I am trying to document an already existing application using javax.ws.rs annotations to define what headers (#HeaderParam) and parameters (#QueryParam) a specific endpoint needs. This information would them be used to generate a swagger page for the application.
public Response SampleFunction(#RequestBody(...),
#QueryParam(...),
#HeaderParam(...),
#HeaderParam(...),
#HeaderParam(...),
etc etc etc){
return doStuff()
}
I have identified a set of "#HeaderParam" which are required for all endpoints.
I need to know if there is any way for me to define the #HeaderParam only once and use that definition for all endpoints and, since this is an already existing application, I need to do this change without any major code refactorization.
We believe to have found a solution for this matter.
By declaring the #HeaderParam globally they appear for all endpoints without having to repeat the declaration for each endpoint.
Something like this:
#Path("/")
public class myClass{
#HeaderParam("Parameter_one")
#Parameter(example = "example_one)
Type parameter_one
#HeaderParam("Parameter_two")
#Parameter(example = "example_two)
Type parameter_two
public Response SampleFunction(#RequestBody(...),
etc etc etc){
return doStuff()
}
}
In this particular case, Parameter_one and Parameter_two will become available on the Swagger page for all endpoints.

Is there a way to get the request body with GET request?

I have this api:
#Path("test")
#GET
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public Parameter performTest(Parameter in) {
System.out.println(in);
}
but the in always returns null. I can change #GET to #POST and it works but I'm not really performing an create or update so using post seems odd.
Is there a way to get the body with a GET request with jersey?
TL;DR The correct solution is to use POST.
"I can change #GET to #POST and it works but I'm not really performing an create or update so using post seems odd"
Why is that odd? POST is not limited to create/update operations.
The specification (RFC 7231, section 4.3.3. POST) says:
The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics. For example, POST is used for the following functions (among others):
Providing a block of data, such as the fields entered into an HTML form, to a data-handling process;
Posting a message to a bulletin board, newsgroup, mailing list, blog, or similar group of articles;
Creating a new resource that has yet to be identified by the origin server; and
Appending data to a resource's existing representation(s).
To paraphrase, POST means "here's some data, please process it for me".
Sure, "process" often means "store", as in create/update, but that is not the only way to process data.
In your case, "process" means "run test, using these parameters".

RESTEasy: How to fall back to other matching resource methods?

In a RESTEasy application I need to determine at runtime if a certain path can be handled by a specific resource method, based on it's path/query parameters. If it can't be handled I want the request to fallback to other methods. E.g.:
#Path("/")
class MyResource {
#GET
#Path("{path : .*}")
public Response handleRedirects(#PathParam("path") String path) {
if (hasRedirectFor(path)) {
return redirectTo(path);
}
else {
//somehow pretend that this method didn't exist and fallback to the next best match
}
}
#GET
#Path("img/{image}")
public Response handleImage(#PathParam("image") String someParam) {
return createImageResponse(image);
}
#GET
#Path("{template : .*\\.html}")
public Response handleTemplate(#PathParam("template") String template) {
return createTemplateResponse(template);
}
}
Is this somehow possible, without having to use a RequestFilter? (I don't want to use a RequestFilter since then I need to implement URL matching for handleSometimes myself).
EDIT: The comments requested to provide more details, so I changed the example to match closer to my real world situation. I have a typical webserver that handles all sorts of requests, in the above example I reduced that to just images and templates. For legacy reasons there are some incoming links from 3rd parties to URLs that don't (or no longer) exists, but which we don't want to break. We therefore want to serve redirects on those URLs, which is what the handleRedirects function is supposed to do.
Unfortunately there is overlap in the patterns for legacy and supported urls, which prevents me from writing #Path annotations to statically route to the correct method. Moreover, I only know if I can actually generate a redirect from legacy -> new when I examine the path at runtime, if this fails I want to fall back to the other methods. I therefore want to be able to determine in the method itself whether I can handle the request or not, and let RESTEasy fallback to the next matching resource if it can't. Usually this is something were filters would come in handy, but then I loose the ability to automatically extract path parameters or to route to different methods, which I really like to keep.

retrieve data from post in JAX-RS

The server is sending data in JSON as HTTP POST, and I am using jax-rs to handle and retrieve data.
I could use #Pathparam or #queryparam based on what I wanted, but data doesnt like in either of those. Not in header either, if I am right, as they content something like content-type, date and some similar sort. How do I retrieve data from POST?
#POST
#Path("/foo")
public void foo(){ //do i need to put sth in parameter paranthesis to get?
//handle the data!! but how??
}
I suggest you take a look at JAX-RS Entity Providers. I will explain to you how marshalling and unmarshalling is done to and from the response and request stream, respectively.
Basically you have MessageBodyReaders and MessageBodyWriters (the former being the one the unmarshall from the request stream. How is works say you have a method like so
#POST
#Consumes(MediaType.TEXT_PLAIN)
public Response postString(String s) {}
The String s, like any other method parameter without an annotation is treated as the body of the request. (Note a method can only have one non-annotated parameter; that is a request can only have one body). So what happens is the JAX-RS (implementation's) runtime will look through the registry of providers (MessageBodyReaders to be exact) to look for one that can handle unmarshalling a body of type text/plain into a String. There are some standard readers for some standard types, and this is one that is available for free.
Now in the case of JSON, say we have this
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response postJson(String json) {}
This can be done also because there is a writer that can handle this. Basically a String parameters can be handled most of the time. It is not difficult to make an InputStream into a String, a String parameter we will usually get support for free.
But what if we want unmarshal to a different type, say Foo
class Foo {
String bar;
String baz;
}
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response postJson(Foo foo) {}
And we had JSON like
{ "bar" : "barValue", "baz": "bazValue" }
We can do this, but we need a custom reader. Luckily there are some already out there. We just need to add the library dependency to out project. For example, Jackson (I'd say the de facto JSON processor in Java) has a reader for us. It's in the dependency
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.5.0</version>
</dependency>
We can just register the JacksonJsonProvider into our application. Then we will be able to use POJOs from our JSON. (For more help on registering this, please provider more information about what JAX-RS implementation you are using, and show your application configuration, whether it's web.xml or Java config)
Some Resources:
See an answer here that describes Jackson use better (with documentation)
See here if you are confused about the #Consumes annotation

Is there a way to access HttpRequest type inside a #Controller method

I have tried to find the answer to this, but I cannot seem to find what I am looking for. So I apologize if this question already exists.
PROBLEM:
I want to be able to access the request type of a request inside of a generic method within my Controller.
DESCRIPTION:
Using Spring ROO and Spring MVC, I have developed a small web service that will respond with certain tidbits from a database when queried. In one of my controller classes, I have some methods that handle some variety of GET, PUT, POST, etc., for the URIs that are mapped within the #RequestMapping parameter.
For example:
#RequestMapping(method = RequestMethod.Get, value = "/foo/bar")
#ResponseBody
public ResponseEntity<String> getFooBar() {
// stuff
}
If a request is made to the web service that it is not currently mapped, a 405 error is returned (which is correct), but I want to return more information along with a 405 response. Maybe respond with something like:
"I know you tried to execute a [some method], but this path only handles [list of proper methods]."
So I wrote a short method that only has the RequestMapping:
#RequestMapping(value = "/foo/bar")
I have found that the method with this mapping will catch all unhandled request types. But I am having trouble accessing the information of the request, specifically the type, from within the method.
QUESTION:
A. How can I access the request type from within the method? OR
B. Is this the right approach? What would be the right approach?
EDIT
ANSWER:
I added a HttpServletRequestobject to the method parameters. I was able to access the method type from that.
I tried using HttpRequest, but it didn't seem to like that much.
Thanks all!
You can add a method parameter of HttpServletRequest, but I think you'd be better off continuing to reply with 405. A client should then make an HTTP OPTIONS call (see How to handle HTTP OPTIONS with Spring MVC?) and you can return the list of allowed methods there.
A. you can access request if you mentioned it as parameter in controller method
public ... getFooBar(HttpRequest request) {
...
}
B. you do not need to add any other description as the 405 status is descriptive.
In answer to "A", just add "HttpRequest req" as an additional argument to your controller methods. Spring will automatically inject a reference to the request, and you can play with headers to your heart's content.
In answer to "B" - "What would be the right approach", how about this?
In order to return that 405, Spring has raised a MethodArgumentNotValidException. You can provide custom handling for this like so:
#ExceptionHandler(MethodArgumentNotValidException.class)
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ResponseBody
public MyMethodArgumentMessage handleMathodArgumentNotValidException(
MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
MyMethodArgumentMessage myMessage =
new MyMethodArgumentMessage(result.getFieldErrors());
return myMessage;
}
You should take a look at the #ExceptionHandler annotation. This lets you add methods such as the following to your controller. You can define your own exceptions and appropriate custom handlers for them. I use it to return well-structured XML and JSON from REST services. Although for it to work, you need to throw specific exceptions from your controller methods.
A good walk-through of using this was provided by Petri Kainulkainen in his blog:
http://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-adding-validation-to-a-rest-api/

Categories

Resources