JSON getting nested in a POJO - java

I have a POJO class as:
public class D{
private JSONObject profileData;
public JSONObject getProfileData ()
{
return profileData;
}
public void setProfileData (JSONObject profileData)
{
this.profileData = profileData;
}
}
Now I populate this class like:
for (int i =0; i<identities.size();i++){
D d = new D();
d.setProfileData(profileData);
dList.add(d);
}
I create JSON object for profileData from GSON using a HashMap:
profileDataInJson = new JSONObject(gson.toJson(map1));
Where the signature of profileDataInJson is: JSONObject profileDataInJson = null;
Now the resultant JSON is like:
"profileData":{"map":{"ioCinema":"firstValue","ioSIMAvailable":"firstKey","Name":"onePair"}}
Wherein I get an unwanted object called map inserted in my main profileData object.
However when I print this inside the loop I get
{`"ioCinema":"firstValue","ioSIMAvailable":"firstKey","Name":"onePair"}`
Whish is exactly what I want inside profileData object, without nesting the map object.
How do I solve this?
"I am already aware that I can achieve this by converting the type of profileData in D class from JSONObject to String, which will induce escape characters - However I am looking for a generic solution"
EDIT:
map1 is constructed in two ways, depending on user input and both ways are as follows:
if (args.length >= 4 && args[1].equalsIgnoreCase("onePair")) {
map1 = new HashMap<>();
String key1 = args[2];
String value1 = args[3];
map1.put(key1, value1);
profileDataInJson = new JSONObject(gson.toJson(map1));
}
And:
if (args.length >= 1 && args[0].equalsIgnoreCase("update")) {
if (args.length >= 2)
profileData.setName(args[1] != null ? args[1] : "");
if (args.length >= 3)
profileData.setSIMAvailable(args[2] != null ? args[2] : "");
profileDataInJson = new JSONObject(profileData);
}
Signature: ProfileData profileData = new ProfileData();
The thing which puzzles me is when I try to traverse profileData and try to fetch the json object by name "map" I get a nullPointer exception

You don't need to use Gson to convert hashmap to a json object.
Simply use:
profileDataInJson = new JSONObject(map);

Add custom serializer to Gson, so that Gson serialize the org JSON as expected by you.
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(JSONObject.class, new JsonSerializer<JSONObject>() {
#Override
public JsonElement serialize(final JSONObject src, final Type typeOfSrc,
final JsonSerializationContext context) {
return new JsonParser().parse(src.toString()).getAsJsonObject();
}
});
gsonBuilder.create().toJson(map1);
This will return {"ioCinema":"firstValue","ioSIMAvailable":"firstKey","Name":"onePair"}

Related

Java boon JSON parser removing null values from output

I have a small function which takes an input JSON string, parses it using boon into a Map, replaces a value for a particular key, returns back the JSON string of the modified Map.
The code is as follows:
// inputJson = {"key3":"A","key2":"B","key1":null,"keyX":[{"x":2019,"y":123,"z":456},{"x":2017,"y":234,"z":345},{"x":2018,"y":456,"z":567}]}
private static String sorter(String inputJson) {
JsonParserAndMapper mapper = new JsonParserFactory().strict().create();
Map<String, Object> map = mapper.parseMap(inputJson);
List<?> l1 = (List<?>) map.get("keyX");
sort(l1, Sort.sortBy("x"));
map.replace("keyX", l1);
for (String x: map.keySet())
System.out.println(map.get(x));
String outputJson = toJson(map); // problem seems to be here
return outputJson
// outputJson = {"key2":"B","key3":"A","keyX":[{"x":2017,"y":234,"z":345},{"x":2018,"y":456,"z":567},{"x":2019,"y":123,"z":456}]}
The problem is, when I do toJson(map) it removes the key with null values. So, if inputJson contains a key with a null value, it doesn't appear in the output. (Notice: key1 is missing in the output)
How can I parse this without losing the null fields?
Using toJson you are using a default serialiser factory. From boon source code:
public class JsonFactory {
private static ObjectMapper json = JsonFactory.create();
public static ObjectMapper create () {
JsonParserFactory jsonParserFactory = new JsonParserFactory();
jsonParserFactory.lax();
return new ObjectMapperImpl(jsonParserFactory, new JsonSerializerFactory());
}
....
)
Instead of using toJson try using a serialiser factory with includeNulls()
JsonSerializer factory = new JsonSerializerFactory().includeNulls().create();

How to sum up two json values in java android?

Can any one tell me, how to sum two JSON objects values? Say, for an example:
First JSON
{
"json_obj":20,
}
Second JSON
{
"json_obj":40,
}
Here what I wanted is, I'm trying to create one JSON as same as like the above one, but i need to sum up two values of the JSON object "json_obj" and finally need to show it as like the below JSON
Resultant JSON
{
"json_obj":60
}
How to achieve this?
Try this,
JSONObject jsonObject1 = new JSONObject(First_JSON);
JSONObject jsonObject2 = new JSONObject(Socond_JSON);
JSONObject jsonObject3 = new JSONObject();
jsonObject3.put("json_obj", jsonObject1.getInt("json_obj")+jsonObject2.getInt("json_obj"));
Try this:
public String getAddedValues(String firstJson, String secondJson, String key){
JSONObject first = new JSONObject(firstJson);
JSONObject second = new JSONObject(secondJson);
int value = first.getInt(key) + second.getInt(key);
JSONObject output = new JSONObject();
output.put(key, value);
return output.toString();
}
Invoke it passing your json Strings and the "json_obj" String as key.
The idea is that you forst need to convert the json string into a Java object. Then you do your calculations, and finally you create another JSONObject with the result. JSONObject.toString() returns the common String representation you would expect as output :-)
You can try something like that:
public class CalcObj {
public int json_obj;
}
public String sumTwoJsons(String json1, String json2) {
Gson _gson = new Gson();
CalcObj obj1 = _gson.fromJson(json1, CalcObj.class);
CalcObj obj2 = _gson.fromJson(json2, CalcObj.class);
CalcObj objSum = new CalcObj();
objSum.json_obj = obj1.json_obj + obj2.json_obj;
return _gson.toJson(objSum );
}

How to modify the JSON data and return the updated JSON data

We have a requirement to update the JSON data in middle and need to return the updated JSON data using java. Also it should support any type of JSON data.
ex:
Assume {object:{"color":"red","shape":"Triangle"}} is the JSON data and in this we need to update the shape value to Rectangle and we need to return the updated JSON data as below:
{object:{"color":"red","shape":"Rectangle"}}
For this we need to pass the element path ( which element we need to update) and updateText and JSON Data to the JAVA code.
here is the methodCall:
updateValue("object/shape", "Rectangle", "{object:{"color":"red","shape":"Triangle"}}")
We tried below code using Gson library. But with this code we are able to update the targeted Json element, but the requirement is to return the entire JSON data with the updated value.
So please suggest how do we re-build the JSON data with the updated text.
Below is the code we tried to update the Json Data.
public String updateValue(String keyPath, String updateText, String jsonText) {
String[] keys = keyPath.split("/");
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonText);
String result = "";
for(String key : keys)
{
if (jsonObject.get(key) instanceof JsonObject)
{
jsonObject = (JsonObject)jsonObject.get(key);
}
else if(jsonObject.get(key) instanceof JsonArray)
{
JsonArray jsonArray = (JsonArray)jsonObject.get(key);
result = jsonArray.toString();
}
else
{
result = jsonObject.get(key).toString();
}
}
result = result.replace(result, updateText);
return result;
}
The problem lies in the way you do the replacements. When you translate the JsonObject to String, you lose the object, and after replacement, you just have the replaced String. To fix it, you need to operate directly on the object, instead of the String counterpart. Because JsonObject is mutable, holding a reference to the input will reflect the changes. One drawback is you can't replace a value in a JsonArray this way, partly because you don't know which element to replace. To accomplish that, you will need a little more in the input(either the value to replace or the element position).
public String updateValue(String keyPath, String updateText, String jsonText) {
String[] keys = keyPath.split("/");
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = (JsonObject) jsonParser.parse(jsonText);
JsonObject returnVal = jsonObject; // This holds the ref to target json object
JsonPrimitive jp = new JsonPrimitive(updateText);
String finalKey = keys[keys.length - 1];
for(String key : keys)
{
if (jsonObject.get(key).isJsonObject())
{
jsonObject = (JsonObject)jsonObject.get(key);
}
}
jsonObject.remove(finalKey);
jsonObject.add(finalKey, jp);
return returnVal.toString();
}
You can use JsonPath lib for that and try using the following code.
private static final Configuration configuration = Configuration.builder()
.jsonProvider(new JacksonJsonNodeJsonProvider())
.mappingProvider(new JacksonMappingProvider())
.build();
JsonNode updatedJson = JsonPath.using(configuration).parse(originaljson)
.set("use the path to go for value", "new value").json();
json = updatedJson.toString();

Convert JSON object with duplicate keys to JSON array

I have a JSON string that I get from a database which contains repeated keys. I want to remove the repeated keys by combining their values into an array.
For example
Input
{
"a":"b",
"c":"d",
"c":"e",
"f":"g"
}
Output
{
"a":"b",
"c":["d","e"],
"f":"g"
}
The actual data is a large file that may be nested. I will not know ahead of time what or how many pairs there are.
I need to use Java for this. org.json throws an exception because of the repeated keys, gson can parse the string but each repeated key overwrites the last one. I need to keep all the data.
If possible, I'd like to do this without editing any library code
As of today the org.json library version 20170516 provides accumulate() method that stores the duplicate key entries into JSONArray
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("a", "b");
jsonObject.accumulate("c", "d");
jsonObject.accumulate("c", "e");
jsonObject.accumulate("f", "g");
System.out.println(jsonObject);
Output:
{
"a":"b",
"c":["d","e"],
"f":"g"
}
I want to remove the repeated keys by combining their values into an array.
Think other than JSON parsing library. It's very simple Java Program using String.split() method that convert Json String into Map<String, List<String>> without using any library.
Sample code:
String jsonString = ...
// remove enclosing braces and double quotes
jsonString = jsonString.substring(2, jsonString.length() - 2);
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String values : jsonString.split("\",\"")) {
String[] keyValue = values.split("\":\"");
String key = keyValue[0];
String value = keyValue[1];
if (!map.containsKey(key)) {
map.put(key, new ArrayList<String>());
}
map.get(key).add(value);
}
output:
{
"f": ["g"],
"c": ["d","e"],
"a": ["b"]
}
In order to accomplish what you want, you need to create some sort of custom class since JSON cannot technically have 2 values at one key. Below is an example:
public class SomeClass {
Map<String, List<Object>> values = new HashMap<String, List<Object>>();
public void add(String key, Object o) {
List<Object> value = new ArrayList<Object>();
if (values.containsKey(key)) {
value = values.get(key);
}
value.add(o);
values.put(key, value);
}
public JSONObject toJson() throws JSONException {
JSONObject json = new JSONObject();
JSONArray tempArray = null;
for (Entry<String, List<Object>> en : values.entrySet()) {
tempArray = new JSONArray();
for (Object o : en.getValue()) {
tempArray.add(o);
}
json.put(en.getKey(), tempArray);
}
return json;
}
}
You can then retrieve the values from the database, call the .add(String key, Object o) function with the column name from the database, and the value (as the Object param). Then call .toJson() when you are finished.
Thanks to Mike Elofson and Braj for helping me in the right direction. I only wanted to have the keys with multiple values become arrays so I had to modify the code a bit. Eventually I want it to work for nested JSON as well, as it currently assumes it is flat. However, the following code works for what I need it for at the moment.
public static String repeatedKeysToArrays(String jsonIn) throws JSONException
{
//This assumes that the json is flat
String jsonString = jsonIn.substring(2, jsonIn.length() - 2);
JSONObject obj = new JSONObject();
for (String values : jsonString.split("\",\"")) {
String[] keyValue = values.split("\":\"");
String key = keyValue[0];
String value = "";
if (keyValue.length>1) value = keyValue[1];
if (!obj.has(key)) {
obj.put(key, value);
} else {
Object Oold = obj.get(key);
ArrayList<String> newlist = new ArrayList<String>();
//Try to cast as JSONArray. Otherwise, assume it is a String
if (Oold.getClass().equals(JSONArray.class)) {
JSONArray old = (JSONArray)Oold;
//Build replacement value
for (int i=0; i<old.length(); i++) {
newlist.add( old.getString(i) );
}
}
else if (Oold.getClass().equals(String.class)) newlist = new ArrayList<String>(Arrays.asList(new String[] {(String)Oold}));
newlist.add(value);
JSONArray newarr = new JSONArray( newlist );
obj.put(key,newarr);
}
}
return obj.toString();
}

JSON array string to JSONArray Object in Java

I'm new to JSON manipulation in Java and I have a String in the form of a JSON Array with several layers I need to access and put into class attributes. For example, here's my JSON object:
{"JsonObject" : [{"attributeOne":"valueOne",
"attributeTwo":"valueTwo",
"attributeThree":[{"subAttributeOne":"subValueOne",
"subAttributeTwo":"subValueTwo"}],
"attributeFour":[{"subAttributeOne":"subValueThree",
"subAttributeTwo":"subValueFour"}],
"attributeFive":"valueThree"},
{"attributeOne":"valueFour",
"attributeTwo":"valueFive",
"attributeThree":[{"subAttributeOne":"subValueFive",
"subAttributeTwo":"subValueSix"}],
"attributeFour":[{"subAttributeOne":"subValueSeven",
"subAttributeTwo":"subValueEight"}],
"attributeFive":"valueSix"}]}
Lets say I have a class called MyClass that has these attributes, how would i parse this string, knowing this is an array of n Objects, each containing "attributeOne, attributeTwo, ..., attributeFive"?
Here's what I have so far:
public MyClass[] jsonToJava (String jsonObj)
{
ArrayList<MyClass> myClassArray = new ArrayList<MyClass>();
//Somehow create a JSONArray from my jsonObj String
JSONArray jsonArr = new JSONArray(jsonObj); //Don't know if this would be correct
for(int i=0; i<jsonArr.length; i++){
MyClass myClassObject = new MyClass();
myClassObject.setAttributeOne = jsonArr[i].getString("attributeOne");
// How can I access the subAttributeOne and Two under attributeThree and Four?
// add all other values to myClassObject
myClassArray.add(myClassObject);
}
return myClassArray;
}
As you can probably tell, I'm fairly new to programming :P Thanks in advance for the help!
Try Jackson JSON:
ObjectMapper mapper = new ObjectMapper(); // can reuse, share globally
User user = mapper.readValue(jsonObj, User.class); //method overloaded to take String
grabbed this two liner from:
http://wiki.fasterxml.com/JacksonInFiveMinutes
http://jackson.codehaus.org/0.9.9/javadoc/org/codehaus/jackson/map/ObjectMapper.html
Should convert your JSON strong to an object. In a Java EE context you may be able to get this unmarshalling functionality at an endpoint with the appropriate annotation.
The way you are trying to do it is painful and involved.
I would suggest that you use a library like GSON and let it do the heavy lifting.
http://code.google.com/p/google-gson/
The documentation has object examples: https://sites.google.com/site/gson/gson-user-guide#TOC-Object-Examples
For your example you can use recursion something like:
public Object getChild(Object parent, int index) {
if (parent instanceof JSONArray) {
try {
Object o = ( (JSONArray)parent ).get(index);
if( o instanceof JSONObject ){
parent = ((JSONObject) ( o ) ).getMap();
return parent;
}
if( o instanceof Double ){
parent = (Double) o;
return parent;
}
if( o instanceof Integer ){
parent = (Integer) o;
return parent;
}
....
} catch (JSONException e1) {
e1.printStackTrace();
}
}
if (parent instanceof JSONObject) {
parent = ( (JSONObject)parent ).getMap();
}
if (parent instanceof Map<?, ?>) {
Map<?, ?> map = (Map<?, ?>) parent;
Iterator<?> it = map.keySet().iterator();
for (int i=0; i<index; i++){
it.next();
}
return map.get(it.next());
}
else if (parent instanceof Collection<?>) {
Iterator<?> it = ((Collection<?>) parent).iterator();
for (int i=0; i<index; i++){
it.next();
}
return it.next();
}
//throw new IndexOutOfBoundsException("'" + parent + "'cannot have children!");
return null;
}
But its a bit complicated (+bad practice to use instanceof) and you don't want to reinvent the wheel. So use GSON or Jackson.
Gson gson = new Gson();
String myClassStr = gson.toGson(MyClassInstance);
....
Myclass yourClass = gson.fromJson(myClassStr, Myclass.class);

Categories