Spring MVC - Deserialize JSON array - javascript

I'm trying to pass data to my controller using Ajax and JSON.
I've got an HTML table and I've got to send multiple coordinates of that table to my controller. So I made a Javascript array containing anonymous objects of this kind :
{
DAY: someIndex,
HOUR: someOtherIndex
}
and let this array be called coordinates, I serialized it like this:
JSON.stringify(coordinates)
so then in an ajax call (type: POST) I used data: JSON.stringify(coordinates).
In my document ready I used :
$.ajaxSetup({
headers : {
Accept : "application/json; charset=utf-8"
}
});
And my controller looks like this:
#RequestMapping(value = "/{id}", method = RequestMethod.POST)
public #ResponseBody
String update(#PathVariable int id, #RequestBody String coordinates, HttpServletResponse response) {
// Do something here to convert it in my complex structure
}
However I don't know what the type should be for the parameter coordinates.
I'm using GSON. And I wasn't able to deserialize it easily. I tried using this solution, but it wouldn't work. (Kept asking to cast types for some reason.)
Since I didn't think it'd be possible to deserialize this correctly, I tried to serialize the coordinates as another format (just a JSON array of strings where the coordinates are split by a token (;) here
So my array the javascript objects are created like this in a foreach:
coordinates.push( someIndex.toString() + ";" + someOtherIndex.toString() );
And I kept the stringify part.
So now when I POST the data to my controller, I output the value with System.out.println(coordinates) and the output looks weird.
%5B%220%3B8%22%5D=
for this object in the Javascript console : ["0;8"].
So my questions :
Is this a good approach?
Is it possible to deserialize a JSON array into some java types? Such as List<Coordinate> ? ( I've tried using this type instead of String in my controller, but it would give me an error 415 - Unsupported media type)
If I'm using the String approach, is there a way to translate that gibberish into something I want?

You get %5B%220%3B8%22%5D= on server side, cause jQuery by default serializes data to query string.
You need to set the content type of the request to application/json using contentType jQuery option.
Then you'll probably want to take a look at some implementation of GsonHttpMessageConverter for simpler RequestBody conversion. Here is one and it looks like there's one in spring for android so maybe you can use that.

Related

How to pass a 2d array of numbers to my .Net controller?

I have a 2d javascript array like this
[[2,3],[13,4],[1,19]]
and I want to pass it to my .Net controller
My controller header looks like this
public async Task<ActionResult> UpdateOrder(int[,] order)
My put call looks like this
updateOrder(order: number[][]): Observable<any> {
return this.http.put(this.baseUrl + 'members/edit/set-order/' + order, {});
}
but I'm getting an error when I hit the controller saying:
'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Int32[,]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\nPath '', line 1, position 2.'
I think you might need to use List<List<int>> type instead of int[,] in c# from default c# JSON serializer
public async Task<ActionResult> UpdateOrder(List<List<int>> order)
You don't need to go through (manual) de/serialization and you don't need a List<List<int>>. I'm able to pass a 2d array of ints with a payload like [[1,2],[3,4],[5,6]] and the below API interface.
public async Task<IActionResult> Test(int [,] ints)
Isn't it your url in the request? You treat the order like a string to cat to the url and the body is empty. And when the body is empty, you see that error you're getting. I think what you need is:
return this.http.put('yourUrl', order, {});
See put. (assuming Angular)

java pass string web request to non string #RequestParam

I am working on a react application that has a java backend. The react frontend sends a URL request to a java web service controller, and within that webservice controller, the variable types are defined. Since a URL request is a string I’m having trouble dealing with non-string values. And since Javascript is not a strongly-typed language like Java I cannot definie variable types on the front end.
Web Request Example:
localhost:8080/filteredCSV.json?status=UNDER_ACTIVE_REVIEW,AUTHORIZED_BY_DWB,UNDER_CONSTRUCTION,CONSTRUCTION_COMPLETED&engineerEmail=null&issues=null&date=null
Web Service Controller:
#RequestMapping(value = "/filteredCSV.json")
#ResponseBody
public WebserviceResponse<?>filteredCSV(
#RequestParam(value="status") ArrayList status,
#RequestParam(value="engineerEmail") ArrayList engineerEmail,
#RequestParam(value="issues", required=false) Boolean issues,
#RequestParam(value="date", required=false) Local Date date){
return service.filteredCSV(status, engineerEmail, issues, date);
}
If the Boolean or Date values are null, then null is getting passed as a string which causes a TypeMismatch Error and the program stops. I do not appear to have a way to change the string to to a non-string null value once it hits the web service controller. I understand why this is occurring, but I am not sure if there is a way to work around it so that I can pass null as a value and not null as a string. Am I just screwed? Is there not a way to deal with this?
You're not sending null as a value, you're sending a string that contains the word 'null.
Send no value "" instead of the string value 'null'. This is what the #RequestParameter is expecting when it should be ignoring a parameter.
#RequestParameter docs
If you can't edit the javascript you still have some options ... what spring is really doing there is data binding values from the http request to instances of Java variables. You can override or bypass this as you need. (This sort of approach is the 'old' way of doing this and the very problem spring annotations hope to solve).
#RequestMapping(value = "/filteredCSV.json")
#ResponseBody
public WebserviceResponse<?>filteredCSV(HttpRequest request){
String date = request.getParameter('date');
// Convert date if not 'null' here, and so on
}
I like the suggestion posted by #zmf, However If want find other work arounds. Please refer some of the approaches I think will work:
Solution 1: You can introduce a filter, and parse all the request parameters as string. When you encounter null as string do not send the param further, it will be considered as null at controller level.
Solution 2: Replace RequestParam type like Date, Boolean with String. You can then process accordingly.

Converting JS object to json string using JSON.stringify

I have four textboxes which contain json string which I create by calling json.stringify on various js objects..
eg. '["users.name","users.username"]' (This is the value of one textbox)
What I want to do is create a single json string from these four json strings and send them to the backend using POST..
So I create a object and add them like this
tmp = {}
tmp["columns"] = $("#sc").val();
/*adding more data....*/
$.ajax("/api/backend", {
data: JSON.stringify(tmp),
/* more ajax code...*/
});
The data that gets sent is of the following format..
{"columns":"[\"users.name\",\"users.username\"]"}
This is not a string but a json object...
Now when I do the following..
tmp1= JSON.stringify(tmp)
and Post using..
$.ajax("/api/backend", {
data: JSON.stringify(tmp1),
/*more code below..*/
The data that gets sent is of the following format and is string..
"{\"columns\":\"[\\\"users.name\\\",\\\"users.username\\\"]\"}"
This string has a lot of '\' characters which needs to be taken into account in the backend.
Is this the right way of handling my problem or am I doing something wrong?
Thanks
It depends on what you are trying to achieve.
If you want to send to the server a JSON that combines all JSON in your inputs, you'd better parse the JSON in your inputs, prior to adding them to you tmp object. That way, you get an object containing objects, rather than an object containing JSON strings.
Retrieving JSON from inputs would be like this:
tmp["columns"] = JSON.parse($("#sc").val());
See that you are storing objects within your tmp object, rather than JSON strings. Then, you can just send that object as JSON to your server.
Thus, your server would receive this:
"{\"columns\":\"[\"users.name\",\"users.username\"]\"}"
Which, I believe, looks much better. I hope that helps.

how to send string array as a response to ajax call from servlet

I made a ajax call from my jsp to servlet. when I want to return string then it is working fine. But I want to send response as a String array then its not working. Is it possible that I can send string array from servlet as a ajax response.
String[] roleAccess=null;
response.setContentType("text/html");
try{
roleAccess=new String[23];
roleAccess[0]="";
roleAccess[1]="checked";
roleAccess[2]="";
response.getWriter().write(roleAccess.toString());---this part I need to change.
Send the ajax response in json format by encoding the array in json and return it.
You can use Gson and then encode your array like:
String jsonRoleAccess = new Gson().toJson(roleAccess, roleAccess.class);
response.getWriter().write(jsonRoleAccess);
// OR do a one liner:
response.getWriter().write(new Gson().toJson(roleAccess, roleAccess.class));
And on the Javascript end, you can access it as a json object
// Assuming you've read the ajax response into var roleAccess
var checked = roleAccess[1];
You want to marshall the array as a JSON data type. The format returned by Java's array class is not in a format that JavaScript understands.
You should also wrap your array inside of an Object because of a security issue of passing top-level arrays back as JSON.
See Why are top level json arrays a security risk
Write it out to JSON instead. Javascript can't understand the result of a Java array's toString() method ([Ljava.lang.String;#5527f4f9), but I know it can understand JSON.
If you're only ever going to be using a string array and you don't want to use any more libraries:
public static String toJSON(String[] array)
{
String json = "[\"";
for (String s : array)
{
json += s + "\",\"";
}
return json.substring(0, json.length() - 2) + "]";
}
Depending on what Javascript framework you're using on your client-side, your JSON will be available as the xmlHttpRequestObject.responseText. AngularJS stores it in the $http.get().success method's first data parameter. jQuery stores it in the $.ajax({success}) method's first data parameter. Angular and jQuery automatically validate and eval it to an [object Object] for you, but xmlHttpRequestObject.responseText doesn't.

Can an HTML encoded string be converted to JSON?

I'm getting encoded data from the server, which is encoded using .NETs WebUtility.HtmlEncode.
This data is then displayed and needs to be sent back to the server for some operations. During this time, it is converted to JSON before being sent over using JSON.stringify. All works fine so far.
However, once this reaches the server, it is rejected due to being potentially dangerous. The object that is converted to JSON can have strings with special chars such as -
"This is John&#39s account" originally "This is John's account"
Or "John earns in &#165" originally "John earns in ¥"
My belief is that these encoded string values are interfering with the JSON being properly formed.
Is there any way in Javascript that I can JSONify HTML encoded strings?
EDIT: In case it's not clear, the data is already encoded when i do JSON.stringify(data).
An example of my data -
row[0] = {column1, column2, column3}
Where each column is an HTML encoded string such as "This is John&#39s account"
Considering that a JSON object with a string would look like this
{ 'member1' : 'some string with &#165' }
I don't believe it's the JSON at fault. It is far more likely that you are passing the JSON object to a method via GET instead of POST.
As a particular example, the Microsoft MVC3 framework will throw an error about it being unsafe if you submit JSON via a GET method and don't specify to allow GET behavior.
The reason for this can be seen in this answer.
I think you can achieve this functionality in three steps:
Create a partial view.
Call this partial view by passing your string values in it and perform action there.
Return your partial view via JSON and replace it with old one.
But returning the partial view via JSON is bit tricky, I mean you cannot just return the partial view via JSON. First you need to convert the partial view in string and the return this string. Below method will you how to achieve this:
public string RenderRazorViewToString(string viewName, object model)
{
ViewData.Model = model;
using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
return sw.GetStringBuilder().ToString();
}
}
This method will convert the partial view in string and return it back to server via JSON. You need to pass to parameter in it, first is the partial view name and second is model. Hope you will get solution of your problem by this.
The solution in the end, was more of a hack, I added an annotation -
[ValidateInput(false)]
to my function on the back-end, so that it wouldn't try to validate my JSON string.

Categories

Resources