Adding multiple Json node into one Using Jackson - java

I am trying to create Json Structure like the below one
{
"properties": {
"a": {
"b": 1,
"c": "2",
"d": 3,
"e": 4
},
"f": {
"g": 5,
"h": "6",
"i": 7,
"j": 8
}
}
}
but I could not.
I have written following code
for(Annotation a : annotationList) {
ObjectNode objectNode1 = readAnnotation(a);
String name= getName(key);
objectNode.putPOJO(name, objectNode1);
propertiesObjectNode.put("properties", objectNode1);
}
to create a JSON but eventually i have only one node in properties.
I got following Json
{
"properties" : {
"f" : {
"g" : 5,
"h" : "6",
"i" : 7,
"j" : 8
}
}
}

propertiesObjectNode.put("properties", objectNode1);
This line is inside a for loop, so you are overwriting it with each iteration. At the end you are left with just 1 node which was a result of last iteration.

Maybe I'm off base here, but if you are using Jackson, why not use the ObjectMapper class. It will convert a POJO to JSON.
ObjectMapper mapper = new ObjectMapper();
MyPojo pojo = new MyPojo();
String json = mapper.writeValueAsString(pojo);
If you wanted to setup something like you have, jackson can take the map and output the json version.
You would have something like:
Map<String, Object> a = new HashMap<String, Object>();
a.put("b", 1);
a.put("c", "2");
Map<String, Object> f = new HashMap<String, Object>();
f.put("g", 5);
f.put("h", "6");
Map<String, Object> propWrapper = new HashMap<String, Object>();
propWrapper.put("a", a)
propWrapper.put("f", f)
Map<String, Object> props = new HashMap<String, Object>();
props.put("properties", props);
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(props);
And that should output the structure you're looking for. It would be better to use your own POJO to get a more meaning full structure, but this should provide an idea.

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

Converting Nested json into dot notation json

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

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.

How to load a JSON file into java that has unique name for each record?

For example my JSON file look like this;
{
"Test1": {
"A": {},
"B": "1",
"C": "2",
"D": "3"
},
"Test2": {
"A": {},
"B": "4",
"C": "5",
"D": "6"
},
"Test3": {
"A": {},
"B": "7",
"C": "8",
"D": "9"
},
"Test4": {
"A": {},
"B": "10",
"C": "11",
"D": "12"
}
...
...
}
This would have been simple if the file only contained a few records, but in my case I'm dealing with thousands of records. For simpler version I've used gson library but not sure how I could load this JSON file which has unique name for each record into Java.
***************UPDATE*******************************
I now managed to read it raw and Map the data. However, still have a minor issue.
This is the code I used to Map
ObjectMapper mapper = new ObjectMapper();
File jsonFile = new File(jsonFilePath);
Map<String, Object> mapObject = mapper.readValue(jsonFile,
new TypeReference<Map<String, Object>>() {
});
System.out.println(mapObject.get("Test1"));
I'm getting below results, which is fine. However, not sure how I could obtain the data within "values" of the map.
{A={}, B=1, C=2, D=3}
I tried below to re-map but it's failing as expected, because the keys no longer are surrounded by double quotes (see above)!
Map<String, Object> nestedObject = mapper.readValue(
mapObject.get("Test1").toString(),
new TypeReference<Map<String, Object>>() {
});
If you know your objects all contain the same keys A, B, C and D then you could create a class that maps a single object
class MyEntry {
/**
* You've tagged the question "gson" but your example code uses Jackson so I've
* written this class with Jackson annotations rather than Gson ones.
*/
#JsonProperty("A")
public Object a; // or a more specific type if you know one
#JsonProperty("B")
public String b;
#JsonProperty("C")
public String c;
#JsonProperty("D")
public String d;
}
and then unmarshal the JSON as a Map<String, MyEntry>
Map<String, MyEntry> mapObject = mapper.readValue(jsonFile,
new TypeReference<Map<String, MyEntry>>() {
});
System.out.println(mapObject.get("Test1").b); // prints 1

Categories

Resources