Dojo grids implement sorting by by issuing requests to REST webservices like so:
GET http://server/request?sort(+id)
Where sort(+id) is the direction (+/-) and the column to sort on.
Currently I'm doing this, and it works, but its ugly:
#GET
#Path("request/")
#Produces(MediaType.APPLICATION_JSON)
public Collection<RequestDataWithCurrentStatus> getAllRequests() {
Collection<RequestDataWithCurrentStatus> col = new ArrayList<RequestDataWithCurrentStatus>();
....
//handle the various types of sorting that can be requested by the dojo widget
String queryString = this.request.getQueryString();
//parse the dojo sort string 'sort(+id)' and sort
...
return col;
}
This method uses a RESTEasy injected #Context private HttpServletRequest request to get access to the raw query string.
I feel like I should be able to map this query string to one of RESTEasy's #*Param annotations in my getAllRequests() invocation. But according to the documentation for RESTEasy, there doesn't seem to be a good mapping to the screwy dojo query string from the doc. I want to do something like this:
#GET
#Path("request/")
#Produces(MediaType.APPLICATION_JSON)
public Collection<RequestDataWithCurrentStatus> getAllRequests( #DojoQueryParam String sort) {
...
}
How do I marshal dojo grid query strings to RESTEasy webservice methods the right way?
I have scarce experience with the old stores / dojox grids, but in case you are using dojo/store/JsonRest: You can change the way it sends the sort param with sortParam. Shamelessly snagged from the reference guide:
var store = new JsonRest({
target: "/FooObject/",
sortParam: "sortBy"
});
This should make requests on the form /foo/bar?sortBy=+id.
http://dojotoolkit.org/reference-guide/1.8/dojo/store/JsonRest.html#sorting
Related
I'm using a javascript library called tabulator to display data inside tables on the client side.
The Tabulator js library provides a feature to encode a representation of filters in the query parameters of an ajax request. For example, here's what the query params look like:
https://host/myEndpoint?size=10&page=1&filters%5B0%5D%5Bfield%5D=username&filters%5B0%5D%5Btype%5D=like&filters%5B0%5D%5Bvalue%5D=filteredBy
Here's the same url decoded:
https://host/myEndpoint?size=10&page=1&filters[0][field]=username&filters[0][type]=like&filters[0][value]=filteredBy
If possible, I'd like to have a Resteasy endpoint like this:
#GET
#Path("/myEndpoint")
#Consumes("application/json")
#Produces("application/json")
public Response myEndpoint(#QueryParam("page") Integer page,
#QueryParam("size") Integer size,
#QueryParam("filters") List<Filter> filters) {
resteasy interprets page and size no problem, but filters is always a list of size 0.
My Filter bean has 3 fields named field, type, and value with a constructor with single String argument as described here.
But it doesn't seem like resteasy is recognizing and parsing the filters query param? Is it possible to parse this type of nested array structure query parameters in resteasy?
filters[0][field]=username&filters[0][type]=like&filters[0][value]=filteredB
I'm still hoping that there's a better way, but here's a possible solution that works for me for now at least:
#GET
#Path("/myEndpoint")
#Consumes("application/json")
#Produces("application/json")
public Response myEndpoint(#QueryParam("page") Integer page,
#QueryParam("size") Integer size,
#Context UriInfo uriInfo) {
for(String key : uriInfo.getQueryParameters().keySet()) {
// check if key starts with something like `filters[0]`
// and then parse it however you need.
}
}
In my Spring web application, I have an API that accepts requests with application/x-www-form-urlencoded content type.
#RequestMapping(value = "/do-it", method = {RequestMethod.POST})
public String test(#ModelAttribute("request")RequestDTO request,HttpServletRequest
httpServletRequest, Map<String, Object> model, RedirectAttributes redirectAttributes){
.....
}
My RequestDTO has following fields in it.
public class RequestDTO {
private String paramOne;
private String paramTwo;
// standard getters and setters
}
This implementation works fine, all the request params get mapped to the request dto as expected. However, now I have this requirement to accept the requests with the fields in following pattern.
param_one, param_two
I understand that, using #JsonProperty annotation on the fields in my request dto is not gonna work in my case since the request is not in the type of application/json.
The only way I have found to solve the issue is creating new setters like following (which looks ugly in my opinion when it comes to naming convention).
public void setParam_one(String param_one) {
this.paramOne = param_one;
}
Can some one help me to find a better way to get this done? I cannot change the param names in original request dto.
Thank you..!
I was able to get this done. Thanks to #neetash for guiding me.
Everything I needed to have was a Custom HandlerMethodArgumentResolver to map the post request body data to the object that I wanted to get.
I followed following linked tutorial to implement it. It contains every single thing someone needs to know to create a HandlerMethodArgumentResolver.
https://www.petrikainulainen.net/programming/spring-framework/spring-from-the-trenches-creating-a-custom-handlermethodargumentresolver/
I have a list of ids which I need to pass as an argument to be displayed in JSON format. Specifically, i put the values in a List and would like my GET method to return them as:
[ 1, 5, 12,...]
I tried using GenericList, but I get a MessageBodyWriter error:
MessageBodyWriter not found for media type=application/json, type=class java.util.ArrayList, genericType=java.util.List<java.lang.Long>.
I'm using Jersey 2.16, and I've had no problems outputting lists of custom classes. The code is here:
#GET
#Path("{name}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUsersByName(#PathParam("name") String name){
List<Long> userIds = userService.getUserssByName(name);
GenericEntity<List<Long>> list = new GenericEntity<List<Long>>(userIds){};
return Response.ok(list).build();
}
UserService queries a hashmap for all the users whose name matches a certain name and returns a list of their keys:
public List<Long> getUserssByName(String name){
List<Long> ids = new ArrayList<>();
for (Entry<Long, User> entry : users.entrySet()){
User user = entry.getValue();
if (user.getName().equals(name)){
ids.add(entry.getKey());
}
}
return ids;
}
How can I get that list to be displayed as I've stated above?
I think this explanation-answer will serve better than just "fixing" your code
By default, jersey provides a set of entity providers that can be used for given media types. For application/json, the following types are provided by default:
byte[]
String
InputStream
Reader
File
DataSource
StreamingOutput
To add support for serialization of other types to json is a bit of a rocky slope with the tools you are currently working with. I'll explain...
Jersey is just a framework for developing RESTful web services in java. There was a time when REST didn't exist (or wasn't seen as useful) and before that concept came about there were already many concrete implementations to facilitate Http data transfer. JAX-RS was one of them. This was during a time when javascript was likely in its infancy and XML largely ruled the world wide web. JAX-RS wasn't designed to natively prevent type erasure, and type erasure is precisely what we are trying to achieve. For me to go through the extremely long-winded solution of implementing the behaviors in MessageBodyWriter would be reinventing the wheel, and no one likes to reinvent the wheel! But, if you are interested in writing your own entities, or you are interested in learning what entities are and how to customize them, head over to https://jersey.java.net/documentation/latest/message-body-workers.html. Reading this document will outline what exactly is going on with your issues.
Solution
Choose a service. Learn it, and do not reinvent the wheel. There are many services out there that can achieve this. My favorite tool is Gson. It is a Java library developed by Google to convert Java objects into their JSON representation and vice versa.
Want to know how simple this is to fix your code?
#GET
#Path("{name}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUsersByName(#PathParam("name") String name){
List<Long> userIds = userService.getUserssByName(namee);
Type listType = new TypeToken<List<Long>>() {}.getType();
Gson gson = new Gson();
String userIdList = gson.toJson(userIds, listType);
return Response.ok(userIdList).build();
}
Now, jersey supports application/json for String entity responses. Pretty much all of your responses will be represented as a String, type erasure is prevented, and you become a more happy developer.
Hope this helps!
You have to convert the list to array.
#GET
#Path("{name}")
#Produces(MediaType.APPLICATION_JSON)
public Response getUsersByName(#PathParam("name") String name){
List<Long> userIds = userService.getUserssByName(namee);
Long[] userIdArray = userIds.toArray();
return Response.ok(userIdArray).build();
}
I want to upload a list of objects to my webserver through a REST API. I'm not sure if it's possible to do it with a REST call?
The object looks like this:
class Position {
private Date date;
private Double latitude;
private Double longitude;
}
Can I do it with something like this:
http://www.example.com/positions?userId=abc&position1=position1&position2=position2 ?
Or should I create a JSON representation of it and upload/put that to the webserver?
You should be able to do this using the Jersey REST framework. It might be enough just to enable the POJO mapping feature.
We do something similar in our project, where we marshal Java data types into JSON, and return that in our HTTP response.
Use http POST instead of GET. You don't have to use json.
Maybe it's a newbie question so sorry in adavnce :)
I'm having a REST API that returns JSON objects. I'm trying to build a web-site with 2 page:
First page presents a table that presents article titles (let's say we have 'article id', 'author name', 'title'). The 'article id' column is clickable
Second page presents a single article.
I want to be able to click on the id column from the first page, perform a GET request to get the JSON object for the article and then present it nicely in the single-article page. I want the url after the GET request to be something like: `http://[web-server-name]/article/[id]
If I'm writing a static page the uses jQuery to fetch the JSON object then the url will not be in the resources format I'm looking. If I'll return HTML from the REST server it will be ugly both to maintain such page and to couple the logic with the presentation.
What would be the correct way of doing it?
Thanks!
You can have to methods declared at the same #Path but that #Produces two different mime types, the good one is selected accordingly to the Accept header sent by the client:
#GET
#Path("/article/{id}")
#Produces(MediaType.APPLICATION_JSON)
public Response getArticle(#PathParam("id") long id) {
Article myArticle = getArticleById(id);
return Response.ok(myArticle);
}
#GET
#Path("/article/{id}")
#Produces(MediaType.TEXT_HTML)
public Response getArticleHtml(#PathParam("id") long id) {
InputStream myHtml = getClass().getClassLoader().getResourceAsStream("/path/to/html.html");
return Response.ok(myHtml).build();
}
But that let your Jax-RS implementation serve static resources for which it is not designed to.
Or you can use a Single Page Javascript framework like AngularJS