Creating a JSON object in MonoTouch (C#) - json

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));

Related

How to extract the a value from a JSON object by matching the key in a Map using Java 8?

I'm using Java 8 and jackson to try and get an int value from a json object. Here is some similar code I used to verify the structure.
HashMap<String, Object> myMap = new HashMap<String, Object>();
myMap
.entrySet()
.stream()
.forEach(x -> System.out.println(x.getKey() + " => " + x.getValue()));
and the result:
myKey1 => {"number":1}
myKey2 => {"number":1}
myKey3 => {"number":2}
What I'm trying to do is use the key, like myKey1 to find the json value i.e. {"number":1} and pull out the actual number, which for that key is 1.
However, I don't all know the values of the key's, just the key I want to match up. So I have to do this dynamically. I know the structure of the values and that is always the same, except the number can be different.
I think because I don't know the keys and their order, plus I'm using entrySet, that is forcing me into using Optional, which is making this more difficult.
Here is my code where I'm actually using the key to pull the json value:
Optional<Object> object = myMap.entrySet().stream()
.filter(e -> e.getKey().equals(myKey))
.map(Map.Entry::getValue)
.findFirst();
However, the stream pulls back
Optional[{"number":1}]
and I can't seem to get the number out so I can return it from a method. I don't actually
have a Java class for the object, so I assume that is why it's returning Optional as I was getting a compile error without it, but I'm not sure.
Any ideas as to the right way to do this?
Why iterating over all the entries of the map and do a linear search by key, to get the value of the entry?
Just get the value directly:
Object value = myMap.get(myKey);
Now, with regard to the number inside value, as you say you don't have a class that represents the values of the map, the most likely thing is that the JSON library you're using is creating a Map for each value. So from now on, let's assume that the values are actually some implementation of Map:
Integer = null;
if (value != null) {
// What's the type of the value? Maybe a Map?
if (value instanceof Map) {
Map<String, Object> valueAsMap = (Map<String, Object>) value;
number = (Integer) valueAsMap.get("number");
}
}
I'm assuming the numbers are Integers, but they can perfectly be Long instances or even Doubles or BigDecimals. Just be sure of the exact type, so the second cast doesn't fail.
EDIT: For completeness, here's the code for when the values are not maps, but of some class that represents a json node. Here I'm using JsonNode from Jackson library, but the approach is very similar for other libs:
Integer = null;
if (value != null) {
if (value instanceof JsonNode) {
JsonNode valueAsNode = (JsonNode) value;
number = (Integer) valueAsNode.get("number").numberValue();
}
}
findFirst() returns an Optional. You need to call .get() or .orElse() or .orElseThrow() after you call findFirst().
You can then cast the Object to JsonNode and retrieve the value. Here is the full code:-
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> myMap = new HashMap<String, Object>();
myMap.put("myKey1", mapper.readTree("{\"number\":1}"));
myMap.put("myKey2", mapper.readTree("{\"number\":1}"));
myMap.put("myKey3", mapper.readTree("{\"number\":2}"));
System.out.println(getNumberUsingMapKey(myMap, "myKey3"));
}
private static int getNumberUsingMapKey(Map<String, Object> map, String key) throws Exception {
return Optional.of(map.get(key))
.map(o -> ((JsonNode) o).get("number").asInt())
.get(); //or use one of the following depending on your needs
// .orElse(-1);
// .orElseThrow(Exception::new);
}
//or use this method
private static int getNumberUsingMapKeyWithoutOptional(Map<String, Object> map, String key) throws Exception {
Object o = map.get(key);
return ((JsonNode) o).get("number").asInt();
}
Output
2
Unfortunately I didn't describe my problem statement well from the start, but this is the final working code that I was able to piece from the other answers.
This is what the data structure looked like. A key that had a value which was a JSON object that had a key and an int, in other words a nested JSON object.
Key: myKey1 Value:{"number":1}
Key: myKey2 Value:{"number":1}
Key: myKey3 Value:{"number":2}
I'm posting it in case some else runs into this use case. This may not be the best way to do it, but it works.
Object value = myMap.get(keyName);
ObjectMapper mapper = new ObjectMapper();
String jsonString = (String) value;
JsonNode rootNode = mapper.readTree(jsonString);
JsonNode numberNode = rootNode.path("number");
System.out.println("number: " + numberNode.intValue());
and the result:
number: 1

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;
}
}

How does play.libs.Json.fromJson handled a List<T> in Java?

I'd like to use the Json library that comes with the play 2.1 framework.
But I'm stuck with deserializing a json object back into a java List.
With gson, you can write s.th. like
Type type = new TypeToken<List<XYZ>>(){}.getType();
List<XYZ> xyzList = gson.fromJson(jsonXyz, type);
Is there a way to do the same with play.libs.Json.fromJson ?
Any help appreciated.
Edit (17.12.2013):
I did the following to work around the problem. I guess there is a better way, but I didn't found it.
List<MyObject> response = new ArrayList<MyObject>();
Promise<WS.Response> result = WS.url(Configuration.getRestPrefix() + "myObjects").get();
WS.Response res = result.get();
JsonNode json = res.asJson();
if (json != null) {
for (JsonNode jsonNode : json) {
if (jsonNode.isArray()) {
for (JsonNode jsonNodeInner : jsonNode) {
MyObject mobj = Json.fromJson(jsonNodeInner, MyObject.class);
response.add(bst);
}
} else {
MyObject mobj = Json.fromJson(jsonNode, MyObject.class);
response.add(bst);
}
}
}
return response;
The Json library for Play Java is really just a thin wrapper over the Jackson JSON library (http://jackson.codehaus.org/). The Jackson way to deserialize a list of custom objects is mentioned here.
For your case, once you parse the json from the response body, you would do something like this, assuming MyObject is a plain POJO:
JsonNode json = res.asJson();
try{
List<MyObject> objects = new ObjectMapper().readValue(json, new TypeReference<List<MyObject>>(){});
}catch(Exception e){
//handle exception
}
I'm assuming you were asking about Play Java based on your edit, Play Scala's JSON library is also based on Jackson but has more features and syntactic sugar to accommodate functional programming patterns.
You can use the following code:
List<YourClass> returnedRoles = new ObjectMapper().readValue(jsonString
,TypeFactory.defaultInstance().constructCollectionType(List.class,
YourClass.class));

How to genearte JSON on the client

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)

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)