How to genearte JSON on the client - json

In the project, I have to send complex JSON commands form the server to the client. Is it effective to generate JSONObjects ( Strings, Numbers, etc.) convert them to the string and then send them via RequestBuilder or is there a more effective method.
Is it effective to convert JSON objects to string (via the .toString method on the Object)
Code example:
JSONObject retObject = new JSONObject();
retObject.put("NumberVar", new JSONNumber(1));
retObject.put("StringVar", new JSONString("HelloWorld"));
JSONArray arrayVar= new JSONArray();
for (int i = 0; i < 5; i++) {
arrayVar.set(i,
new JSONString("Array"));
}
retObject.put("EventParameters", arrayVar);
System.out.println(retObject.toString());
Output:
{"NumberVar":1, "StringVar":"HelloWorld", "EventParameters":["Array","Array","Array","Array","Array"]}
Regards,
Stefan

The solution you have will work.
If you want to do it more efficiently, and you only want to support modern browsers with support for JSON.stringify(), you can work in JavaScriptObjects instead of JSONObjects and use this native method:
private static native String stringify(JavaScriptObject jso) /*-{
return JSON.stringify(jso);
}-*/;
Alternatively, you can stringify a JSO by doing:
String json = new JSONObject(jso).toString();
JavaScriptObjects are more efficient because they are represented in the final compiled code as JS objects, while JSONObjects are represented as emulated Java objects. The second solution will mean less overhead while you construct the JSO, but comparatively more (than the first) when you stringify it.
Your solution will work just fine though.

There's also AutoBeans.
public interface MyJsonFactory extends AutoBeanFactory {
AutoBean<MyJsonObj> myJsonObj();
}
public interface MyJsonObj {
#PropertyName("NumberVar")
int getNumberVar();
#PropertyName("NumberVar")
void setNumberVar(int val);
#PropertyName("StringVar")
String getStringVar();
#PropertyName("StringVar")
void setStringVar(String val);
#PropertyName("EventParameters")
List<String> getEventParameters();
#PropertyName("EventParameters")
void setEventParameters(List<String> val);
}
MyJsonFactory factory = GWT.create(MyJsonFactory.class);
AutoBean<MyJsonObj> bean = factory.myJsonObj();
MyJsonObj obj = bean.as();
// bean and obj are 2 distinct view on the exact same data
obj.setNumberVar(1);
obj.setStringVar("HelloWorld");
List<String> list = new ArrayList<String>(5);
for (int i = 0; i < 5; i++) {
list.add("Array");
}
obj.setEventParameters(list);
System.out.println(AutoBeanCodex.encode(bean).getPayload());
The #PropertyName is needed is as your JSON property names do not align with the AutoBean conventions (inspired by Java Beans ones), where getNumberVar() gets a numberVar property (with lower-case n)

Related

Exclude a data member from JSon serialization

This is with the Docusign Rest api. When I call ToJson() on an EnvelopeDefinition, it returns the correct info, but I would like it to not serialize the base64 array for when I am writing this out to a log file. I tried using the [JsonIgnore] directive, but that stopped the array from being serialized altogether. Do I need to override the Serialize method on this class or just create another method, something like ToJsonForLogging() and not serialize that array?
I have created an extension method that will work for you. You can call this extension method in your code as follows
string json = envelopeDefinition.ToJsonLog(logDocumentBase64:false)
I am copying the DocumentBase64 into a temporary List and then using .ToJson() function to log without the documentBase64 property.
public static class EnvelopeDefinitionExtensions
{
public static string ToJsonLog(this EnvelopeDefinition envDefinition, bool logDocumentBase64 = true)
{
if (logDocumentBase64) return envDefinition.ToJson();
var tempDocumentBase64List = new List<string>();
foreach(var doc in envDefinition.Documents)
{
tempDocumentBase64List.Add(doc.DocumentBase64);
doc.DocumentBase64 = null;
}
string json = envDefinition.ToJson();
int i =0;
foreach(var doc in envDefinition.Documents)
{
doc.DocumentBase64 = tempDocumentBase64List[i];
i++;
}
return json;
}
}

serializing dates correctly with javascript serializer in asp.net mvc3

i am experimenting with backbone javascript after seeing the Tekpub MVC3 screencasts by Rob Connery
i like his Massive database access, but as soon as it is getting a bit more complex than a video can possibly show you.
i added extra fields to my database, being datetime fields.
however, this javascript serializer, converts them into strings
public string toJson(dynamic content) {
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoObjectConverter() });
var json = serializer.Serialize(content);
return json.ToString();
}
this makes a datetime from this: {19/10/2011 1:58:27} into this: "19/10/2011" (*values taken from the quickwatch window on runtime..., basicly comes down to a loss in precision and it now being a basic string.
after backbone pushes that back to the server (on a model.save() call), i try to update the model like Rob does:
[HttpPut]
public ActionResult Edit()
{
var model = SqueezeJson();
model.UpdatedAt = DateTime.Now;
_movies.Update(model, model.Id);
return CmoJSON(model);
}
for the SqueezeJson function, check his source
resulting in an error like this:
Arithmetic overflow error converting expression to data type datetime.
i kind of expected this to happen since i noticed the dates being dumped into strings, i had no idea how it would go back into a date time using massive.
has anyone worked with massive and dates, in a context like this (serializing to and from json)?
i know the problem isn't necessarily massive itself, it's the json serializiation that dumbs it down into a string with loss of data, and doesn't return it to a proper date.
but still, maybe someone has a better way of doing this...
any idea's are welcome...
I have encountered the same question with you.
You can change Serialize method in ExpandoObjectConverter like:
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
ExpandoObject expando = (ExpandoObject) obj;
if(expando!=null)
{
Dictionary<string,object> result = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> item in expando)
{
var value = item.Value ?? "";
if (value is DateTime)
result.Add(item.Key, ((DateTime) value).ToString("yyyy.MM.dd"));
else
{
result.Add(item.Key, value.ToString());
}
}
return result;
}
return new Dictionary<string, object>();
}

GWT HashMap to/from JSON

I might be getting a bit tired tonight but here it goes:
I'd like to have GWT HashMap to/from JSON. How would I achieve this?
In other words, I'd like to take an HashMap, take its JSON representation, store it somewhere and get it back to its native Java representation.
Here is my quick solution:
public static String toJson(Map<String, String> map) {
String json = "";
if (map != null && !map.isEmpty()) {
JSONObject jsonObj = new JSONObject();
for (Map.Entry<String, String> entry: map.entrySet()) {
jsonObj.put(entry.getKey(), new JSONString(entry.getValue()));
}
json = jsonObj.toString();
}
return json;
}
public static Map<String, String> toMap(String jsonStr) {
Map<String, String> map = new HashMap<String, String>();
JSONValue parsed = JSONParser.parseStrict(jsonStr);
JSONObject jsonObj = parsed.isObject();
if (jsonObj != null) {
for (String key : jsonObj.keySet()) {
map.put(key, jsonObj.get(key).isString().stringValue());
}
}
return map;
}
Not the most optimized, but should be easy to code: use JSONObject.
Iterate over your map's entries and put them in a JSONObject (converting each value to a JSONValue of the appropriate type), then call toString to get the JSON representation.
For parsing, get a JSONObject back using a JSONParser, then iterate over the keySet, geting the values and putting them in your map (after unwrapping the JSONValues)
But beware of the keys you use! You cannot use any kind of key as a property name in JS; and JSON processing in the browser always involve going through a JS object (or implementing the JSON parser yourself, which won't perform the same)

Creating a JSON object in MonoTouch (C#)

How do i manually create a JSON object in monotouch(4.0)?
The System.JSON namespace is available, (JsonObject, JsonArray, jSonPrimitive and JsonValue) but those are all abstract, so i can't just do this :
JsonObject myObject = new JsonObject();
I need to manually build a JSON object, and do not want to use DataContractSerialisation.
For reference purposes :
-I will need to transfer that JSON object to a server with a web call later. (but i can handle that part)
Use JSON.net http://json.codeplex.com/
As it turns out, after a long time of trying and searching ; only the JsonPrimitiveconstructor and the JsonObject constructor can be used.
JsonPrimitive and JsonValue can both be cast to JsonValue.
the JsonObject requires a KeyValuePair<string, JsonValue>
if i define functions like this :
public static KeyValuePair<String, JsonValue> IntRequired(string key, int val)
{
return new KeyValuePair<String, JsonValue>(key, new JsonPrimitive(val));
}
i can create a json object like this :
JSonObject myObject = new JsonObject();
myObject.add(new IntRequired("id",1));

WCF restful returning JSON by using Entity Framework Complex

recently I have set up a WCF restful service with EF4.
It all worked out when returning XML format response. however when it comes to JSON, I got 504 Error. unable to return json data, WCF Resful Service .NET 4.0
By digging deeper by using Service Trace Viewer:
I found this error:
'The type 'xxx.DataEntity.AppView'
cannot be serialized to JSON because
its IsReference setting is 'True'. The
JSON format does not support
references because there is no
standardized format for representing
references. To enable serialization,
disable the IsReference setting on the
type or an appropriate parent class of
the type.'
The "AppView" is a complex object class which generated by EF4 from a store procedure.
I spend quite a bit time google how to disable the IsReference, very little result so far.
anyone? with any solutions?
thanks in advance
Code:
[OperationContract]
[WebInvoke(Method = "GET",
BodyStyle = WebMessageBodyStyle.Wrapped,
UriTemplate = "App/{id}/{format}")]
AppView FuncDetail(string id, string format);
public AppView FuncDetail(string id, string format)
{
SetResponseFormat(format);
return AppSvcs.GetById(id);
}
private void SetResponseFormat(string format)
{
if (format.ToLower() == "json")
{
ResponseContext.Format = WebMessageFormat.Json;
}
else
{
ResponseContext.Format = WebMessageFormat.Xml;
}
}
I ran into exactly the same issue. It only happened on one of my service methods where I was trying to return JSON serialised Entity objects. For all my other methods I was returning JSON serialised data transfer objects (DTOs), which are stand-alone and not connected to the Entity framework. I am using DTOs for data posted into methods. Often, the data you send out does not need all the data you store in the model or the database e.g. ID values, updated dates, etc. The mapping is done in the model class, like so:
public partial class Location
{
public static LocationDto CreateLocationDto(Location location)
{
LocationDto dto = new LocationDto
{
Accuracy = location.Accuracy,
Altitude = location.Altitude,
Bearing = location.Bearing
};
return dto;
}
It may seem a bit clunky but it works and it ensures that you only send the data fields you intended to send back. It works for me because I only have 5 or 6 entities but I can see that it would get a bit tedious if you have lots of classes.
I was running into the same problem, as caused by using the auto-generated ADO Entity Models. I have not found a direct fix for this issue, but as a work around, I serialize the response as json explicitly.
So in your example, the AppView FuncDetail looks like this:
public object FuncDetail(string id, string format)
{
SetResponseFormat(format);
// where AppSvc is the object type and the enumerable list of this type is returned by the GetById method, cast it to a json string
return JSONSerializer.ToJson<AppSvc>(AppSvcs.GetById(id));
}
Here are the Serializers that I'm using:
public static class GenericSerializer
{
public static DataTable ToDataTable<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = new DataTable();
// column names
PropertyInfo[] oProps = null;
if (varlist == null) return dtReturn;
foreach (T rec in varlist)
{
// Use reflection to get property names, to create table, Only first time, others will follow
if (oProps == null)
{
oProps = ((Type)rec.GetType()).GetProperties();
foreach (PropertyInfo pi in oProps)
{
Type colType = pi.PropertyType;
if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition()
== typeof(Nullable<>)))
{
colType = colType.GetGenericArguments()[0];
}
dtReturn.Columns.Add(new DataColumn(pi.Name, colType));
}
}
DataRow dr = dtReturn.NewRow();
foreach (PropertyInfo pi in oProps)
{
dr[pi.Name] = pi.GetValue(rec, null) == null ? DBNull.Value : pi.GetValue
(rec, null);
}
dtReturn.Rows.Add(dr);
}
return dtReturn;
}
}
public static class JSONSerializer
{
public static string ToJson<T>(IEnumerable<T> varlist)
{
DataTable dtReturn = GenericSerializer.ToDataTable(varlist);
return GetJSONString(dtReturn);
}
static object RowsToDictionary(this DataTable table)
{
var columns = table.Columns.Cast<DataColumn>().ToArray();
return table.Rows.Cast<DataRow>().Select(r => columns.ToDictionary(c => c.ColumnName, c => r[c]));
}
static Dictionary<string, object> ToDictionary(this DataTable table)
{
return new Dictionary<string, object>
{
{ table.TableName, table.RowsToDictionary() }
};
}
static Dictionary<string, object> ToDictionary(this DataSet data)
{
return data.Tables.Cast<DataTable>().ToDictionary(t => "Table", t => t.RowsToDictionary());
}
public static string GetJSONString(DataTable table)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(table.ToDictionary());
}
public static string GetJSONString(DataSet data)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(data.ToDictionary());
}}
It is a lot clearer to use Entity Metadata instead of Reflection.
The Metadata is pretty extensive.
another way to do this is to use LINQ to create an anonymous type with the subset of fields that you need from your entity and then use JSON.NET to serialize the collection of anon types that you created in the LINQ statement. then persist that collection out as a string by serializing.