Converting Nested json into dot notation json - java

I have a service from where I get a json string response like as shown below
{
"id": "123",
"name": "John"
}
I consume the rest call using HttpClient and converts the json string to Map<String, String> like as shown below.
String url= "http://www.mocky.io/v2/5979c2f5110000f4029edc93";
HttpClient client = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(url);
httpGet.setHeader("Content-Type", "application/json");
HttpResponse httpresponse = client.execute(httpGet);
String response = EntityUtils.toString(httpresponse.getEntity());
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map = mapper.readValue(response, new TypeReference<Map<String, String>>(){});
The conversion from json string to HashMap is working fine, but actually my requirement was sometimes there can be some nested json within the main json, for example in the below json I am having an additional address key which is again a nested json having city and town details.
{
"id": "123",
"name": "John",
"address": {
"city": "Chennai",
"town": "Guindy"
}
}
If any nested json comes I need the make the json like as shown below
{
"id": "123",
"name": "John",
"address.city": "Chennai",
"address.town": "Guindy"
}
Currently I am using jackson library, but open to any other library which will give me this feature out of box
Can anyone help me by giving some suggestion on this.

Here is a recursive method that will flatten a nested Map with any depth to the desired dot notation. You can pass it to Jackson's ObjectMapper to get the desired json output:
#SuppressWarnings("unchecked")
public static Map<String, String> flatMap(String parentKey, Map<String, Object> nestedMap)
{
Map<String, String> flatMap = new HashMap<>();
String prefixKey = parentKey != null ? parentKey + "." : "";
for (Map.Entry<String, Object> entry : nestedMap.entrySet()) {
if (entry.getValue() instanceof String) {
flatMap.put(prefixKey + entry.getKey(), (String)entry.getValue());
}
if (entry.getValue() instanceof Map) {
flatMap.putAll(flatMap(prefixKey + entry.getKey(), (Map<String, Object>)entry.getValue()));
}
}
return flatMap;
}
Usage:
mapper.writeValue(System.out, flatMap(null, nestedMap));

Related

Using HashMap to create complex JSON

I have spent a few days googling this various ways and don't see any that give examples of using HashMap - instead they all refer to Jackson or GSON. I am not able to use these as they cause an issue in Jenkins that will not be addressed (basically everything is super locked down and the work place will not "open" up alternatives)
I have a JSON body that I am attempting to send to a create record API.
For simple JSON body the process is pretty straightforward:
Desired JSON:
{
"owner": {
"firstName": "Steve",
"lastName": "Guy",
"Hair": "brown",
"Eyes": "yes"
"etc": "etc"
},
"somethingElse": "sure"
}
would look like
Map<String,Object> jsonRequest = new HashMap<>();
Map<String,String> ownerMap = new HashMap<>();
HashMap<Object, String> OwnerMap = new HashMap<Object, String>;
OwnerMap.put("firstName","Steve");
OwnerMap.put("lastName","Guy");
OwnerMap.put("Hair","brown");
OwnerMap.put("Eyes","yes");
OwnerMap.put("etc","etc");
jsonRequest.put("owner", OwnerMap);
jsonRequest.put("somethingElse", "sure");
Easy enough
If the JSON gets slightly more complex, I can't seem to figure it out.. and again I cannot use any other dependency for this.
so if I have a JSON Body that I need to send :
{
"customer": {
"address": [
{
"address": "Blah"
}
]
},
"anotherThing": "thing"
}
the same pattern does not work.
Map<String,Object> jsonRequest = new HashMap<>();
Map<String,String> ownerMap = new HashMap<>();
HashMap<Object, String> addressMap = new HashMap<Object, String>;
addressmap.put("address","Blah");
jsonRequest.put("address", addressMap);
jsonRequest.put("owner", OwnerMap);
jsonRequest.put("anotherThing", "thing");
returns as:
{
"owner": {
},
"anotherThing": "thing",
"address": {
"address": "Blah"
}
}
You seem to assume that the inner (for want of a better word) Maps need to be Map<*, String>, and that Map and String are the only things which extend Object.
Something like the following should work fine:
Map<String, Object> json = new HashMap<>();
Map<String, Object> customer = new HashMap<>();
// Could make this a Map<String, Object>[] (array) depending
// on json library used... You don't specify.
List<Map<String, Object>> address = new ArrayList<>();
Map<String, Object> innerAddress = new HashMap<>();
innerAddress.put("address", "Blah");
address.add(innerAddress);
customer.put("address", address);
json.put("customer", customer);
json.put("anotherThing", "thing");

Convert JSONArrays into Map using Java

Trying to write a java class which convert JSON into Map by giving key. Sample method format and steps are below:
public Map<String, Map<String, String> convert(String jsonBody, String key){
Map<String, Map<String, String>> dataMap = new HashMap<String, Map<String, String>>();
Map<String, String> singleEntry = new HashMap<String, String>();
//Iterator<String> --get key from jsonBody
while(itr.hasNext()){
for(upto arary count){
singleEntry.put(jsonBody.getKey(i), jsonBody.getValue(i));
}
dataMap.put(itr.next(), singleEntry);
}
System.out.println(dataMap);
return data;
}
Sample JSON
[
{
"id": 146,
"Name": "John",
"LastName": "Mack",
},
{
"id": 148,
"Name": "Sam",
"LastName": "Rick",
}
]
Expected Output:
id -146, {id=146, Name = John, LastName =Mack}
id -148, {id=148, Name = Sam, LastName =Rick}
Please suggest best API and correct approach. Thanks in Advance.
See here for how to convert a json node to a Map.
See here about how to convert the json array to a map.

Java : Sort JSON String using key

I have a String which is in JSON format. I need to sort this JSON string using attributes but am unable to do it. JSON String is created by reading a CSV file. I do not want to read the CSV again and have to implement it using JSON String only. Is there a way to do that? Please let me know.
JSON String format is :
[
{
"address": "some address",
"name": "some name",
"phone": "some phone",
"age": "some age",
"SSN": "some SSN"
},
{
"address": "abc",
"name": "def",
"phone": "ghi",
"age": "jkl",
"SSN": "mno"
}
]
Please explain.
You can convert the JSONstring into a TreeMap with a Comparator you implement to compare by value, and then convert this TreeMap back to JSON.
See how to create a value Comparator here:
http://www.programcreek.com/2013/03/java-sort-map-by-value/
And then use ObjectMapper to convert the JSON into a map the the map back to JSON:
String json = "{\"address\" : \"def\","
+ "\"name\" : \"ghi\","
+ "\"phone\" : \"jkl\","
+ "\"age\" : \"def\","
+ "\"SSN\" : \"abc\"}";
Map<String, String> jsonMap = new HashMap<String, String>();
ObjectMapper mapper = new ObjectMapper();
jsonMap = (mapper.readValue(json, Map.class));
Comparator<String> comparator = new ValueComparator(jsonMap);
Map<String, String> treeMap = new TreeMap<String, String>(comparator);
treeMap.putAll(jsonMap);
String sortedJson = mapper.writeValueAsString(treeMap);
System.out.println(sortedJson);
Result:
{"SSN":"abc","address":"def","name":"ghi","phone":"jkl"}
Comparator:
public class ValueComparator implements Comparator<String> {
Map<String, String> map = new HashMap<String, String>();
public ValueComparator(Map<String, String> map){
this.map = map;
}
#Override
public int compare(String s1, String s2) {
return map.get(s1).compareTo(map.get(s2));
}
}

Jackson: Cannot deserialize instance of object out of START_ARRAY

I'm getting this error when attempting to parse some JSON previously generated with Jackson. I generate the JSON like so
String ret = "";
ret = mapper.writeValueAsString(message.getPayload());
message.setPayload(ret);
Where message.getPayload() is a HashMap, in this instance containing two strings and a List of various objects. This creates the following malformed JSON
{
"user" : "john d example",
"items" : [ {
"val" : 99.5,
"id" : "phone",
"qty" : 1
}, {
"val" : 15.5,
"id" : "wine",
"qty" : 4
} ],
"address" : "123 example street"
}
Which throws an exception when examined thusly
Map<String, Object> ret = new HashMap<String, Object>();
String s = (String)message.getPayload();
ret = mapper.readValue(s, new TypeReference<Map<String, String>>(){});
How should I properly write this Map to JSON?
TypeReference<Map<String, String>> should be TypeReference<Map<String, Object>>. Jackson is attempting to parse the values as Strings rather than Lists because that is what it expects based on the TypeReference you passed in.

Decoding JSON String for List with names

I am try to decode a JSON string as below
{
"id_value": [
{
"id": "1.1.1.1",
"value": "v1"
},
{
"id": "1.1.1.2",
"value": "v2"
}
]
}
Which is basically a list of id_value object. IdValue is a POJO class with a string variable of id and value.
I am able to decode the JSON string , when I passed in JSON without the list name , as below.
[
{
"id": "1.1.1.1",
"value": "v1"
},
{
"id": "1.1.1.2",
"value": "v2"
}
]
My JAVA code is as below :
String jsonString1 = "{\"id_value\": [{\"id\": \"1.1.1.1\",\"value\": \"v1\"},{\"id\": \"1.1.1.2\",\"value\": \"v2\"}]}";
String jsonString2 = "[{\"id\": \"1.1.1.1\",\"value\": \"v1\"},{\"id\": \"1.1.1.2\",\"value\": \"v2\"}]";
List<IdValue> idValues = null;
try {
Gson gson = new Gson();
idValues = gson.fromJson(jsonString2, new TypeToken<List<IdValue>>(){}.getType());
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println(idValues);
My code works well with jsonString2 , but I am getting the below exception with jsonString1. Both of them are lists , but why it is failing for one and working for other.
com.google.gson.JsonParseException: The JsonDeserializer com.google.gson.DefaultTypeAdapters$CollectionTypeAdapter#67ac19 failed to deserialize json object {"id_value":[{"id":"1.1.1.1","value":"v1"},{"id":"1.1.1.2","value":"v2"}]} given the type java.util.List<com.something.json.IdValue>
Any inputs would be helpful.
Thanks !!
jsonString2 represents a List<IdValue>
jsonString1 represents a Map<String, List<IdValue>>
So, to process jsonString1 you need:
Map<String, List<IdValue>> map = gson.fromJson(json, new TypeToken<Map<String, List<IdValue>>>(){}.getType());
List<idValue> idValues = map.get("id_value");
Here is more general way to get your IdValues from jsonString1 even if there are another entries in it:
Gson gson = new Gson();
JsonParser parser = new JsonParser();
String jsonString1 = "{\"id_value\": [{\"id\": \"1.1.1.1\",\"value\": \"v1\"},{\"id\": \"1.1.1.2\",\"value\": \"v2\"}]}";
JsonElement e = parser.parse(jsonString1);
JsonArray idValueArray = e.getAsJsonObject().getAsJsonArray("id_value");
List<IdValue> idValues = gson.fromJson(idValueArray, new TypeToken<List<IdValue>>(){}.getType());
id_value isn't part of your IdValue POJO. So the TypeToken of List does not know how to map the id_value piece of the JSON string.
Because jsonString1's deserializing type is not same with jsonString2's. If you want to use same deserializing type, you should first do substring.
jsonString1 = jsonString1.substring(s.indexOf("["));
jsonString1 = jsonString1.substring(0, s.lastIndexOf("]") + 1);

Categories

Resources