How can i convert JSON to Java object - javascript

Hi I am having a JSON of following format
{
"elements":[
list1,
list2,
list3
]
}
where list1,list2,list3 are all javascript arrays.
Now I am able to pass this to my controller(am using spring mvc) from a javascript file. Now I want to use the data in the JSON that am sending. I want to map this to a model class and return it another jsp page.
I didn't create a model yet. how can i pull this off?
Please help. Thanks in advance.

use GSON to convert your JSON into java
YourModelClass obj= gson.fromJson(json, YourModelClass .class);

Using Gson, you first need to create a class structure representing your JSON data, so you can create a class like this:
public class Response {
private List<List<YourObject>> elements;
//getter and setter
}
Note that I use class YourObject since you don't specify what type your arrays contain... If the arrays contain just strings for example, replace YourObject by String. If the arrays contain a different object you have to create a class representing the data in your JSON, such as:
public class YourObject {
private String attribute1;
private int attribute2;
private boolean attribute3;
//getters and setters
}
Then, in order to actually parse your JSON response, you just have to do:
Gson gson = new Gson();
Response response = gson.fromJson(yourJsonString, Response.class);
And your JSON data will be used to fill your class structure, so you can access the fields, for example:
String attribute1 = response.getElements().get(i).get(i).getAttribute1();

Hi I used the following code and its working great.
Gson gson = new Gson();
JsonParser jsonParser = new JsonParser();
JsonArray jsonArray = jsonParser.parse(this.plan).getAsJsonArray();
ArrayList<PlanJson> planJsonList = new ArrayList<PlanJson>();
for(JsonElement jsonElement:jsonArray)
{
System.out.println(jsonElement);
PlanJson planJson = gson.fromJson(jsonElement, PlanJson.class);
planJsonList.add(planJson);
}
I found it to be the most easiest to work out for my json structure.

You can use the jackson library. see: http://jackson.codehaus.org/
Here is an example from: http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/
package com.mkyong.core;
import java.io.File;
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
public class JacksonExample {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
// read from file, convert it to user class
User user = mapper.readValue(new File("c:\\user.json"), User.class);
// display to console
System.out.println(user);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Related

Error deserializing JSON with Newtonsoft, C#

I'm receiving the following error:
Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'System.Collections.Generic.Dictionary`2[System.String,System.Collections.Generic.List`1[ReportingDataSchema.CurrentBusinessUnits]]'
because the type requires a JSON object (e.g. {\"name\":\"value\"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {\"name\":\"value\"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array.
JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array. Path 'selectedBusinessUnits', line 1, position 26."} System.Exception {Newtonsoft.Json.JsonSerializationException}
My JSON:
{
"selectedBusinessUnits": [{
"guidNode": "some value",
"businessUnit": "some value",
"fileName": "some value"
}, {
...
}]
}
I'm trying to first transform this response into the following:
public class EnAFileGenerator
{
private Dictionary<string, List<CurrentBusinessUnits>> selectedBusinessUnits;
public Dictionary<string, List<CurrentBusinessUnits>> SelectedBusinessUnits
{
get { return selectedBusinessUnits; }
set { selectedBusinessUnits = value; }
}
}
So that ultimately I can access the array in the JSON, using the following:
public class CurrentBusinessUnits
{
private string guidNode;
private string businessUnit;
private string fileName;
public string GuidNode { get; set; }
public string BusinessUnit { get; set; }
public string FileName { get; set; }
}
The code that's generating the error:
// JSON Data is the parameter from the client, containing the above JSON object
EnAFileGenerator resultArray = JsonConvert.DeserializeObject<EnAFileGenerator>(JSONData);
From what I've read, it seems like my error is a result of the parsing the array (the value for the property selectedBusinessUnits) into the desired C# collection.
After implementing #DavidG's suggestion, I'm still receiving the following:
Error converting value \"{\"guidNode\":\"some value\",\"businessUnit\":\"some value\",\"fileName\":\"some value.xlsx\"}\"
to type 'ReportingDataSchema.CurrentBusinessUnits'. Path 'selectedBusinessUnits[0]', line 1, position 159."}
System.Exception {Newtonsoft.Json.JsonSerializationException}
Prany's solution nearly got me there. I was able to modify that code to utilize the objects I already had:
var files = JObject.Parse(JSONData);
var recList = files.SelectToken("$..selectedBusinessUnits").ToList();
foreach (string item in recList)
{
JObject businessUnit = JObject.Parse(item);
CurrentBusinessUnits currentBusinessUnit = businessUnit.ToObject<CurrentBusinessUnits>();
}
The problem is you are trying to deserialise into the wrong type. you have specified a Dictionary<string, List<CurrentBusinessUnits>> but really you only need a List<CurrentBusinessUnits>:
public class EnAFileGenerator
{
public List<CurrentBusinessUnits> SelectedBusinessUnits { get; set; }
}
You can use Jobject since you're using Newtonsoft. For getting values based on selectedBusinessUnits. Use below
var files = JObject.Parse(YourJson);
var recList = files.SelectToken("$..selectedBusinessUnits").ToList();
foreach (JObject item in recList)
{
foreach (JProperty prop in item.Children())
{
string key = prop.Name.ToString();
string value = prop.Value.ToString();
}
}

Passing dates between c# and javascript

I have an ASP.Net MVC app that returns a view model, which when converted to JSON using system.web.mvc.jsonresult looks as follows:
On the client I'm using KnockoutJS. I use MomentJS to format the value for the VoucherDate so that it can be displayed for humans:
var recsArray = [];
$.each(data.Vouchers, function (key, value) {
recsArray.push(
new edited(
interchangeId,
value.SupplierIsValid,
value.VoucherNo,
value.LegacySupplierId,
value.Transactions,
moment(value.OriginalVoucher.VoucherDate).format('YYYY/MM/DD HH:mm'),
value.OriginalVoucher
)
);
As you can see from the previous code snippet, in addition to pushing the data into an observable array for display in a KOGrid, I also push the entire "OriginalVoucher". This enables the user to edit the value for "LegacySupplierId" and click "Resubmit" which posts back the entire view model as seen below:
self.resubmit = function () {
var data = {
Vouchers: ko.toJS(this.recs),
BatchId: self.batchId(),
InterchangeId: interchangeId,
IsReadWrite: self.isReadWrite,
Interface: self.interface,
ReportClient: self.reportClient
};
$.ajax({
type: "POST",
url: BASE_URL + 'EditBatch/ResubmitRejectedVouchersAsNewBatch',
data: ko.toJSON(data),
I've checked using Fiddler and confirmed that the VoucherDate fields contain values such as /Date(14543712000000)/. My problem is, when reading in the C# controller, all of the dates are presented as 1/1/0001 12:00:00 AM.
I've read that javascript has a date.toISOString() function to convert to a format that C# will be happy with. Is there a better way that trying to find each date field in the javascript view model and executing a conversion against each before posting back to the C# controller
I think I have previously solved this problem using automapper by following instructions here: enter link description here
In my source code I can see that I created the following class but I don't know how / if this gets used:
public class JsonDateTimeTypeConvertor : ITypeConverter<string, DateTime>
{
public DateTime Convert(ResolutionContext context)
{
string jsonDate = context.SourceValue.ToString();
string offsetAsString = Regex.Match(jsonDate, #"\d+").Value;
double offset = System.Convert.ToDouble(offsetAsString);
DateTime ret = DataUtils.ConvertFromUnixTimestamp(offset);
return ret;
}
}
I think it was being used but I've inadvertently disabled it. This probably happened when I changed the type for the ViewModel received by the controller. The previous version of the application worked, so I guess the datetime was being converted correctly - probably by this automapper extension. I have pulled the old version of the code from TFS but can't figure out how it's doing the magic - I wish I'd made better notes at the time! All I have is:
I needed to create a custom type convertor to deal with JSON dates being passed to the EditBatch controller in the format of number of milliseconds since 1900.
I followed the wiki documentation from here:
https://github.com/AutoMapper/AutoMapper/wiki/Custom-type-converters
May be you can use a regex pattern like this. The following code shows ToJavaScriptDate() function that does this for you:
function ToJavaScriptDate(value)
{
var pattern = /Date\(([^)]+)\)/;
var results = pattern.exec(value);
var dt = new Date(parseFloat(results[1]));
return (dt.getMonth() + 1) + "/" + dt.getDate() + "/" + dt.getFullYear();
}
The ToJavaScriptDate() function accepts a value in /Date(ticks)/ format and returns a date string in MM/dd/yyyy format. Inside, the ToJavaScriptDate() function uses a regular expression that represents a pattern /Date(([^)]+))/.
The exec() method accepts the source date value and tests for a match in the value. The return value of exec() is an array. In this case the second element of the results array (results[1]) holds the ticks part of the source date. For example, if the source value is /Date(836418600000)/ then results[1] will be 836418600000. Based on this ticks value a JavaScript Date object is formed. The Date object has a constructor that accepts the number of milliseconds since 1 January 1970. Thus dt holds a valid JavaScript Date object. The ToJavaScriptDate() function then formats the date as MM/dd/yyyy and returns to the caller.
I'm really not a fan of the way the default JavaScriptConverter handles dates. I use the following class. (The CustomString class is kind of a dirty hack to get around the fact that the Serialize command is expected to return an IDictionary. See blog post here: http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/)
public class DateTimeJsonSerializer : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (dictionary == null)
return null;
return new JavaScriptSerializer().ConvertToType(dictionary, type);
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
if (!(obj is DateTime)) return null;
return new CustomString(((DateTime) obj).ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
}
public override IEnumerable<Type> SupportedTypes
{
get { return new ReadOnlyCollection<Type>(new List<Type> { typeof(DateTime), typeof(DateTime?) }); }
}
}
public class CustomString : Uri, IDictionary<string, object>
{
public CustomString(string str) : base(str, UriKind.Relative)
{}
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
public void Clear()
{
throw new NotImplementedException();
}
public bool Contains(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
throw new NotImplementedException();
}
public bool Remove(KeyValuePair<string, object> item)
{
throw new NotImplementedException();
}
public int Count { get; private set; }
public bool IsReadOnly { get; private set; }
public bool ContainsKey(string key)
{
throw new NotImplementedException();
}
public void Add(string key, object value)
{
throw new NotImplementedException();
}
public bool Remove(string key)
{
throw new NotImplementedException();
}
public bool TryGetValue(string key, out object value)
{
throw new NotImplementedException();
}
public object this[string key]
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
public ICollection<string> Keys { get; private set; }
public ICollection<object> Values { get; private set; }
}
To use this in asp.net, I have the following section in my web.config (make sure to replace "AssemblyNameGoesHere" with the assembly that contains the converter class:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="2147483644">
<converters>
<add name="DateTimeConverter" type="DateTimeJsonSerializer,AssemblyNameGoesHere" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
I managed to work-around this by changing the data type on the "VoucherDate" field in the C# model from DateTime to String. I don't currently understand why this works. I also think there must be a better way!?

AngularJS 400 Bad request

I'm trying to implement some post functionality in my app.
I have got the following post method:
restrictLoginAttemptsFromSingleIp: function (id, userId) {
var serviceUri = baseServicesUrlService.getBaseServicesUrl() + "/employee-service/restrict-single-ip";
return $http.post(serviceUri, {restrictLoginAttemptIp: {loginAttemptIds: [id]}, dataOwnerId: userId});
}
My server side is using RESTEasy 3.0.4 with Hibernate validation:
#POST
#Path("/restrict-single-ip")
public Response RestrictSingleIp(#Valid RestrictLoginAttemptIpRequest requestData, #Context HttpRequest request){
return Response.status(200).build();
}
The RestrictLoginAttemptIpRequest class inherits one field (dataOwnerId) of type Long from PostBase:
public class RestrictLoginAttemptIpRequest extends PostBase {
private RestrictLoginAttemptIp restrictLoginAttemptIp;
public RestrictLoginAttemptIp getRestrictLoginAttemptIp() {
return restrictLoginAttemptIp;
}
public void setRestrictLoginAttemptIp(RestrictLoginAttemptIp restrictLoginAttemptIp) {
this.restrictLoginAttemptIp = restrictLoginAttemptIp;
}
}
The RestrictLoginAttemptIp class:
package blah;
import org.hibernate.validator.constraints.NotEmpty;
import java.util.List;
public class RestrictLoginAttemptIp {
#NotEmpty(message = "blah")
private List<Long> loginAttemptIds;
public List<Long> getLoginAttemptIds() {
return loginAttemptIds;
}
public void setLoginAttemptIds(List<Long> loginAttemptIds) {
this.loginAttemptIds = loginAttemptIds;
}
}
I get the following data string from the POST request which seems to be ok:
{restrictLoginAttemptIp={loginAttemptIds=[328]}, dataOwnerId=8}
Can someone please explain me why I get an 400 Bad request error when I invoke that function?
Is this because of Long datatypes? Should I somehow mark them in Javascript to be Longs?
Ok after 4 hours I figured out the problem.
The case is, that I'm reading the POST data (solving permission questions) in a security interceptor. Reading POST data in RESTEasy is a little bit tricky. To create a LinkedHashMap I use Apache IOUtils (https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html) like it is figured out in the next code snippet
String result = IOUtils.toString(requestContext.getEntityStream());
ObjectMapper mapper = new ObjectMapper();
Object obj = mapper.readValue(result, Object.class);
I looked up in my AngularJS interceptor (used for example for putting something in the header of every request) and figured out, that the server cannot read the input stream: java.io.ioexception no content to map to object due to end of input.
At the end the problem was, that after I once read the EntityStream of the ContainerRequestContext it became empty. The solution was to repopulate it after reading POST data. Something like this:
private LinkedHashMap getPostData(ContainerRequestContext requestContext) {
Object obj = null;
try {
String result = IOUtils.toString(requestContext.getEntityStream());
ObjectMapper mapper = new ObjectMapper();
obj = mapper.readValue(result, Object.class);
//IMPORTANT: After you can get the entity stream only once. After reading the entity stream is empty
//so the JSON parser cannot convert EMPTY entity stream into any object. To avoid strange errors (like 400 Bad Request)
//you have to convert the string back to input stream and rewrite the empty entity stream.
InputStream stream = IOUtils.toInputStream(result);
requestContext.setEntityStream(stream);
System.out.println(obj);
} catch (IOException e) {
e.printStackTrace();
}
return (LinkedHashMap) obj;
}
P. S. ObjectMapper comes from Jackson

Return JavaScript object literal, not JSON string, from ASP.NET MVC endpoint

For various reasons, I have switched from ASP.NET MVC's built in JSON serializer (the one that returns a System.Web.Mvc.JsonResult object (see edit below)) to Newtonsoft. I didn't realize until after I began testing that the former returns a JavaScript object literal, while Newtonsoft returns a JSON formatted string.
I like not having to parse JSON strings on the client side — having it already as an object literal is very convenient — but I want to stick with Newtonsoft for other technical reasons.
For example, instead of seeing this result on my client...
"{"Errors":["Please enter a valid email address."],"HasErrors":true}"
...I'd like to see this result:
{"Errors":["Please enter a valid email address."],"HasErrors":true} // no quotes
Is there a way to make Newtonsoft return JS object literals instead of strings?
EDIT
The way my question was framed wasn't the best. There's nothing wrong with the JsonResult type. In fact, the solution still uses it. The only problem was the default Controller.Json methods, which can be overridden to use Newtonsoft (Json.NET) instead of the built-in serializer.
Just write a custom JsonResult that uses Newtonsoft serializer:
Something along the lines:
public abstract class BaseController : Controller
{
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding)
{
return new JsonNetResult
{
ContentType = contentType,
ContentEncoding = contentEncoding,
Data = data
};
}
protected override JsonResult Json(object data, string contentType, System.Text.Encoding contentEncoding, JsonRequestBehavior behavior)
{
return new JsonNetResult
{
ContentType = contentType,
ContentEncoding = contentEncoding,
Data = data,
JsonRequestBehavior = behavior
};
}
}
JsonNetResult.cs:
using System;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
public class JsonNetResult : JsonResult
{
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult()
{
Formatting = Formatting.None;
SerializerSettings = new JsonSerializerSettings();
JsonRequestBehavior = JsonRequestBehavior.DenyGet;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
if (JsonRequestBehavior == JsonRequestBehavior.DenyGet
&& String.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
throw new InvalidOperationException("This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet.");
}
HttpResponseBase response = context.HttpContext.Response;
response.ContentType = !string.IsNullOrEmpty(ContentType)
? ContentType
: "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data != null)
{
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Data);
writer.Flush();
}
}
}
Credit: https://gist.github.com/jpoehls/1424538
Answer is here: How to force ASP.NET Web API to always return JSON?
Excerpt:
Clear all formatters and add Json formatter back.
GlobalConfiguration.Configuration.Formatters.Clear();
GlobalConfiguration.Configuration.Formatters.Add(new JsonMediaTypeFormatter());
EDIT
I added it to Global.asax inside Application_Start().

Android Phonegap - Passing JSONObject to javascript

I'm trying to pass some information from an Android native class to the javascript.
I'm taking a bundle, converts it to JSONObject and passing the string representation of it.
But when trying to parse it in the JS, it fails.
This is what I do:
JSONObject jsonObject = new JSONObject();
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
try {
jsonObject.put(key, value.toString());
} catch (JSONException e) {
// Do nothing
}
}
final String jsStatement = String.format(
"window.doSomething('%s');", jsonObject.toString());
cordova.getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
webView.loadUrl("javascript:" + jsStatement);
}
});
Can you tell me why it's not being parsed in the JS and how can I solve it?
Look into the Javascript Interface annotation which can be used to pass in / access the values from Java directly

Categories

Resources