I'm using Jersey to implement a JAX-RS resource. I've seen lots of different examples on Stack Overflow, various blogs and the Jersey User Guide.
I would like to know what the different overloads can be for a given resource handler. Is there a single source where these are documented?
For example, the following handles an HTTP POST request. The request body is captured as a MultivaluedMap.
#POST
public Response httpPostRequest(MultivaluedMap<String, String> body)
{
...
}
Alternatively, the following overload captures the body as a single String.
#POST
public Response httpPostRequest(String body)
{
...
}
There are other overloads too. How many are there and where are they documented?
It is just a normal Java method that has one or more annotations associated with it. The signature of the method has no particular constraints placed on it by Jersey.
Having said that, you will want to make sure that the various annotations (e.g., #Produces, #Consumes, #PathParam, #QueryParam) are applied to data types that Jersey knows how to map. For example, Jersey has no problem with mapping #PathParam to String or long. Jersey can also work with Java classes that have JAXB annotations, so your method signature can include a JAXB type combined with #Consumes(MediaType.APPLICATION_XML) and Jersey will convert the request content from an XML document to the JAXB Java class.
For example:
#GET
#Produces(MediaType.APPLICATION_XML)
#Path("somepath")
public Foos getFoosByQuery(#PathParam("businessName") String businessName,
#PathParam("businessUnitName") String businessUnitName, #PathParam("fileType") String fileType,
#QueryParam("from") String fromString, #QueryParam("to") String toString,
#DefaultValue("10") #QueryParam("interval") int intervalMinutes,
#DefaultValue("1000") #QueryParam("limit") int limit,
#DefaultValue("false") #QueryParam("errors") boolean errors) {
Here, we see that we have many parameters (with types String, int and boolean) and a return type that is a JAXB-annotated POJO. Jersey pulls the #PathParam values from the path, the #QueryParam values from the query string and converts the return value into an XML document and includes it as the content of the response.
I will also note that the name of the method can be anything we want, so the concept of "overloading" is orthogonal to Jersey. The normal Java overloading rules apply.
It should be obvious from this example that you cannot enumerate all of the possible "overloads" that you can use with Jersey.
Perhaps a different question regarding all of the possible type mappings that Jersey can do would be more in line with what you are looking for.
Related
How to fail on invalid query parameter name with RESTEasy?
Consider a valid REST request like this one: /list?sort-by=date
Then, user makes this request: /list?sort_by=date
See that user replaced hyphen with underscore. It works, but it will ignore parameter and use default sorting (param not mandatory).
With Jackson, if a JSON with invalid member is sent it throws an Exception. I would like a similar behavior to query params (header params would be awesome too). Tested with #BeanParam, but apparently it doesn't use Jackson in this case.
RESTEasy version 3.15.1.
You have to check that in your code. Query params are not in json in standard, you can do that with a class with string constructor.
In fact "sort_by" is not bind to a method parameter, so it's ignored.
If you want that "sort-by" to be mandatory you have to do that in your code :
Required #QueryParam in JAX-RS (and what to do in their absence)
Currently since RESTEasy is built on top of a Servlet, it does not distinguish between URI query strings or url form encoded parameters. Like PathParam, your parameter type can be an String, primitive, or class that has a String constructor or static valueOf() method.
https://docs.jboss.org/resteasy/docs/3.15.1.Final/userguide/html_single/#_QueryParam
I'm working on documenting an API made with RESTeasy + Jackson in Java using Swagger/OpenAPI (version 1.5.18 - I did add in v3 OAS 2.0.1 to try oneOf/anyOf). One of the endpoints takes in a String as a request body, which is then transformed into one of several classes. The documentation needs to display each of these models so that users can see them. The models are defined in another project. Is there a way to do this through annotations? The closest thing I've found is adding #RequestBody(content=#Content(schema=#Schema(oneOf= {class1.class, class2.class}))) but haven't been able to get it to add the model using that. I also tried adding a dummy class with #ApiModel(subTypes={class1.class, class2.class}. I don't want to add additional endpoints for each object type due to code maintainability.
My question is: is it possible to add the models through annotations while leaving the input type as String?
Here is the relevant code:
#POST
#Path("/{filetype}/new")
#Consumes("application/json")
public Response writeFile(
#ApiParam(required=true, allowableValues = "class1, class2") #PathParam("filetype") String filetype,
#RequestBody(content=#Content(schema=#Schema(oneOf= {class1.class, class2.class}))) String inputFile
) {
return validateFileAndSaveToServer(filetype, inputFile);
}
I'm trying to implement a method in a dropwizard resource, that will service a call from a JS frontend (that uses DataTables).
The request has query parameters that look like this:
columns[0][data]=0&columns[0][name]=&columns[0][searchable]=false&columns[0][orderable]=false&columns[0][search][value]=&columns[0][search][regex]=false
columns[1][data]=iata&columns[1][name]=iata&columns[1][searchable]=true&columns[1][orderable]=true&columns[1][search][value]=&columns[1][search][regex]=false
The request comes from a JS frontend implemented with DataTables, and uses server-side processing. Info about how datatables sends the requests here:
https://datatables.net/manual/server-side
I'm having issues defining the data type for the above query parameters. With spring data, we can define it as:
List<Map<String, String>> columns
which can be wrapped in an object annotated with ModelAttribute and it will deserialize fine.
In my app I'm using an older version of dropwizard which depends on jersey 1.19.
I've tried annotating it as a QueryParam, but the app fails at startup.
Method:
#Path("/mappings")
#GET
#Timed
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response getMappings(#QueryParam("columns") List<Map<String, String>> columns) {
// processing here.
}
When I do this, I get:
ERROR [2016-11-07 14:16:13,061] com.sun.jersey.spi.inject.Errors: The
following errors and warnings have been detected with resource and/or
provider classes: SEVERE: Missing dependency for method public
javax.ws.rs.core.Response
com.ean.gds.proxy.ams.application.resource.gui.IataMappingGuiResource.getMappings(java.util.List)
at parameter at index 0 WARN [2016-11-07 14:16:13,070] /: unavailable
My question is: do I have any option other than writing a custom deserializer for it ?
Note: If I grab the request with #Context, I can see that the decodedQueryParams are a MultivaluedMap, which maps String keys like "columns[0][data]" to Lists of String values, which always have a single element, that is the value.
Update:
After some digging, I found the following JAX-RS specification (section 3.2) which explains why my approach isn't valid to begin with:
The following types are supported:
Primitive Types
Types that have a constructor that accepts a single String argument.
Types that have a static method named valueOf with a single String argument.
List, Set, or SortedSet where T satisfies 2 or 3 above.
Source: Handling Multiple Query Parameters in Jersey
So I've tried using just a List instead. This doesn't crash the app at startup, but when the request comes in, it deserializes into an empty list. So the question remains as to what approach is correct.
In fact, you're using such a very different structure from all the common ones we have mapped for Rest Web Services consummation. Also, because of this structural compliance problem, trying to use JSON to marshal/unmarshal the values won't suit, once we haven't object-based parameters being transported.
But, we have a couple of options to "work this situation around". Let's see:
Going with the #QueryParam strategy is not possible because of two main reasons:
As you noticed, there are some limitations on its use regarding Collections other than Lists, Sets, etc;
This annotation maps one (or a list) of param(s) by its(their) name(s), so you need every single parameter (separated by &) to have the same name. It's easier when we think about a form that submits (via GET) a list of checkboxes values: once they all have the same name property, they'll be sent in "name=value1&name=value2" format.
So, in order to get this requirement, you'd have to make something like:
#GET
public Response getMappings(#QueryParam("columns") List<String> columns) {
return Response.status(200).entity(columns).build();
}
// URL to be called (with same param names):
// /mappings?columns=columns[1][name]=0&columns=columns[0][searchable]=false
// Result: [columns[1][name]=0, columns[0][searchable]=false]
You can also try creating a Custom Java Type for Param Annotations, like you see here. That would avoid encoding problems, but in my tests it didn't work for the brackets issue. :(
You can use regex along with #Path annotation defining what is going to be accepted by a String parameter. Unfortunately, your URL would be composed by unvalid characteres (like the brackets []), which means your server is going to return a 500 error.
One alternative for this is if you "replace" this chars for valid ones (like underscore character, e.g.):
/mappings/columns_1_=0&columns_1__name_=
This way, the solution can be applied with no worries:
#GET
#Path("/{columns: .*}")
public Response getMappings(#PathParam("columns") String columns) {
return Response.status(200).entity(columns).build();
}
// Result: columns_1_=0&columns_1__name_=
A much better way to do this is through UriInfo object, as you may have tried. This is simpler because there's no need to change the URL and params. The object has a getQueryParameters() that returns a Map with the param values:
#GET
public Response getMappings(#Context UriInfo uriInfo) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
// In case you want to get the whole generated string
String query = uriInfo.getRequestUri().getQuery();
String output = "QueryParams: " + queryParams
+ "<br> Keys: " + queryParams.keySet()
+ "<br> Values: " + queryParams.values()
+ "<br> Query: " + query;
return Response.status(200).entity(output).build();
}
// URL: /mappings?columns[1][name]=0&columns[0][searchable]=false
/* Result:
* QueryParams: {columns[0][searchable]=[false], columns[1][name]=[0]}
* Keys: [columns[0][searchable], columns[1][name]]
* Values: [[false], [0]]
* Query: columns[1][name]=0&columns[0][searchable]=false
*/
However, you must be aware that if you follow this approach (using a Map) you can't have duplicated keys, once the structure doesn't support it. That's why I include the getQuery() option where you get the whole string.
A last possibility is creating a InjectableProvider, but I can't see many diffs to the getQuery() strategy (since you can split it and create your own map of values).
I have not used #POST before and am not sure about the syntax and how to test. Here's what I have now:
#GET
#Path("classroomAssignmentId/{classroomAssignmentId}/classroomId/{classroomId}/assignmentName/{assignmentName}/assignmentDesc/{assignmentDesc}/assignmentDueDt/{assignmentDueDt}/assignmentDocument/{assignmentDocument}/assignmentStatusId/{assignmentStatusId}/updatedBy/{updatedBy}")
#Produces(MediaType.APPLICATION_JSON)
public ClassroomAssignment getCandidatesAsJson( #PathParam("classroomAssignmentId") int classroomAssignmentId
,#PathParam("classroomId") int classroomId
,#PathParam("assignmentName") String assignmentName
,#PathParam("assignmentDesc") String assignmentDesc
,#PathParam("assignmentDueDt") String assignmentDueDt
,#PathParam("assignmentDocument") String assignmentDocument
,#PathParam("assignmentStatusId") int assignmentStatusId
,#PathParam("assignmentTypeId") int assignmentTypeId
,#PathParam("updatedBy") String updatedBy)
I want to change the #GET to #POST. Need help with syntax and how to test the WS call through a browser.
There are two issues here.
First, merely wanting to express your parameters differently is insufficient for changing the semantics of your call. A POST is fundamentally different from a GET, and both semantics are very clearly defined in REST. You shouldn't switch just for convenience sake.
But second, if you find the theory pedantic and just care about how to practically get this done, you will use something like this:
#POST
#Path("/classroom-assignment)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public ClassroomAssignment getCandidatesAsJson(CandidateObject myObject) {
...
}
Then you will need your JAX-RS provider (RESTEasy, Spring MVC, Restlet, etc.) to perform automatic deserialization of JSON (typically with Jackson) to the CandidateObject POJO, which will have getters and setters mapping to the fields in your original query string of your GET.
At least that's the default serialization, which will be sufficient and easiest.
You will also have a ClassroomAssignment POJO, and your JSON serializer (again typically Jackson) will convert that POJO to JSON.
But ultimately, if a GET worked before, you should probably keep things as GET. Just rethink your design and how the GET call is made.
I am a new comer in terms of web services. I am tasked to convert an existing software component to a web service. I did some research and I decided to use JAX-RS. I am having a difficulty to decide when to use #QueryParam and when to use #Consume because they seems to be able to achieve the same goal.
For example, let say I have a method named read() and it takes a book as an argument.
public class AReader { public void read(Book book){...} }
public class Book { public String author; public String name; }
When translating this using JAX-RS annotation, I could either
Use #POST and #QueryParam to accept the author and name parameter or
Use #POST and #Consumes to consume a text representation of Book in XML or JSON format in the body.
My question is what is the common usage for #QueryParam and #Consume. Is this just a personal preference or there is a common practice?
I found a lot information about usage of #PathParam and #QueryParam but not #QueryParam and #Consumes.
Thanks in advance...
Query parameters are ideally best suited for representing aspects of requests that have nothing to do with a resource representation.
For example, if you are designing a RESTful web service, and if you're creating a new Book via a POST request, then the body of the request should ideally contain the resource representation in the desired media type - application/json, text/xml, application/x-www-form-urlencoded etc. Providing the resource representation via query parameters would not be on the lines of how HTTP-based REST APIs are designed. Additionally, query parameters can be omitted and thus the provided resource representation is incomplete, which would be against the design principles that require complete resource representations to be provided in POST and PUT operations.
Query paremeters would be more suitable for GET requests. Say you want a paginated collection of requests, then you would accept requests like /books?start=0&pagesize=10 to obtain the first 10 books.
You are right when you say you can use #QueryParam and #Consumes to achieve a common goal, but be aware that the semantics of those annotations are very different.
In your case, since you are interested in just two values, both approaches are equivalents in my opinion. If you were working with more complex objects (i.e. POJO with several attributes), I would suggest you let JAX-RS implementations take care of object marshalling/unmarshalling annotating the methods with #Consumes and/or #Produces.
This sample code:
#GET
#Path("/books")
public void books(#PathParam("title") String title, #PathParam("author") String author, #PathParam("ISBN") String isbn, #PathParam("category") String category, #PathParam("price") String price) {
Book book = new Book(title, author, isbn, category, price);
...
}
could be reduced to
#POST
#Path("/books")
#Consumes(MediaType.APPLICATION_XML)
public void books(Book newBook) {
Book book = newBook;
...
}
Additionally, REST architecture brings a new semantics to HTTP verbs and codes. According to its guidelines, you are not supposed to use #POST with #PathParam or even #GET to modify a resource. Please, refer to this link for a brief explanation but feel free to explore it in more details (you can start here).
In JAX-RS, you can use #QueryParam annotation to inject URI query parameter into Java method. for example,
/users/query?url=nini.com
In above URI pattern, query parameter is “url=nini.com“, and you can get the url value with #QueryParam("url").
======
""http://docs.oracle.com/cd/E19776-01/820-4867/ggqqr/ ""