How to Parse JSON with dynamic Keyname? - java

I have a JSON response like this.
{
"array": [
{
"object1": {
"aa": "somevalue1",
"bb": "somevalue2",
"cc": "somevalue3"
}
},
{
"object2": {
"aa": "somevalue4",
"bb": "somevalue5",
"cc": "somevalue6"
}
}
]}
Now I can get a JSON array from above response. I want read the value aa,bb,cc from object object1 and object2 in a for loop.
JSON is dynamic, I mean that object2 can also appear before object1 (in reverse order) and there is chances that I might get one more object(object3) with same structure OR only one (object1 or object2 or object3).
I dont want to do like this as I failed in :
JSONArray jsonArray = json.getJSONArray("array");
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonObject = jsonArray.getJSONObject(i).getJSONObject("object1");
}
So my question is HOW can I read those values aa,bb,cc without depending on object name or number of object (object1 or object2 or object3)?

It looks like each item in the array only has 1 key/value pair which holds another json object which then has several.
If this is the case, then you could probably do something like this:
for (int i = 0; i < jsonArray.length(); i++)
{
JSONObject jsonObject = jsonArray.getJSONObject(i);
JSONObject innerObject = jsonObject.getJSONObject(jsonObject.keys().next().toString());
/// do something with innerObject which holds aa, bb, cc
}
You simply grab the 1st key in the wrapping object, and use that to grab the inner json object.

I think you should have next Java-side structure of classes:
Entity - class that will hold aa, bb and cc fields
Container - a class that will consist of two fields - Name and Entity, where Name can store object1, object2 or whatever.
Then, you should deserialize provided JSON into collection/array of Container entities.
Hope this helps.
Update: please check this example Collection deserialization

You should work with dynamic structures like java.util.Map. Try with this:
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
public class JsonTest {
public static void main(String[] args) {
String json = "{\"array\": [{\"object1\": {\"aa\": \"somevalue1\",\"bb\": \"somevalue2\",\"cc\": \"somevalue3\"}},{\"object2\": {\"aa\": \"somevalue4\",\"bb\": \"somevalue5\",\"cc\": \"somevalue6\"}}]}";
System.out.println(json);
final MyJson parseJsonSpecification = parseJsonSpecification(json);
System.out.println(parseJsonSpecification.array.get(0).get("object1"));
System.out.println(parseJsonSpecification);
}
public static MyJson parseJsonSpecification(String jsonString) {
try {
if (StringUtils.isBlank(jsonString)) {
return new MyJson();
}
MyJson ret;
ret = new ObjectMapper().readValue(jsonString, new TypeReference<MyJson>() {
});
return ret;
} catch (Exception ex) {
throw new IllegalArgumentException("La expresión '" + jsonString + "' no es un JSON válido", ex);
}
}
}
class MyJson {
public List<Map<String, Object>> array;
}

Related

Java Gson parse Json object to array

I'm trying to parse the below Json using the Gson lib in Java. When using other languages, such as C#, this JSON is parsed into an array, however it seems Gson converts this into a set of java attributes (which to be honest, makes more sense to me). Does anyone know if I can change this behaviour of the Gson lib?
{
"Outer": {
"0": {
"Attr1": 12345,
"Attr2": 67890
},
"1": {
"Attr1": 54321,
"Attr2": 09876
}
}
}
The below code demonstrates how Gson parses the array as a JsonObject. To be clear, I realise I've referenced outer as a JsonObject but I was just doing this to demonstrate the code. If I try and reference outer as an JsonArray, the code fails.
String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.setLenient()
.serializeNulls()
.create();
JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");
System.out.println(outer);
System.out.println(outer.isJsonArray());
Result:
{"0":{"Attr1":12345,"Attr2":67890},"1":{"Attr1":54321,"Attr2":"09876"}}
false
//edit
I'm using this current simple Json as an example, however my application of this code will be to parse Json that's of varying and unknown shape. I therefore need Gson to automatically parse this to an array so that the isJsonArray returns true.
TL;DR: See "Using Deserializer" section at the bottom for parsing straight to array.
That JSON does not contain any arrays. An array would use the [...] JSON syntax.
Normally, a JSON object would map to a POJO, with the name in the name/value pairs mapping to a field of the POJO.
However, a JSON object can also be mapped to a Map, which is especially useful when the names are dynamic, since POJO fields are static.
Using Map
The JSON object with numeric values as names can be mapped to a Map<Integer, ?>, e.g. to parse that JSON to POJOs, do it like this:
class Root {
#SerializedName("Outer")
public Map<Integer, Outer> outer;
#Override
public String toString() {
return "Root[outer=" + this.outer + "]";
}
}
class Outer {
#SerializedName("Attr1")
public int attr1;
#SerializedName("Attr2")
public int attr2;
#Override
public String toString() {
return "Outer[attr1=" + this.attr1 + ", attr2=" + this.attr2 + "]";
}
}
Test
Gson gson = new GsonBuilder().create();
Root root;
try (BufferedReader in = Files.newBufferedReader(Paths.get("test.json"))) {
root = gson.fromJson(in, Root.class);
}
System.out.println(root);
Output
Root[outer={0=Outer[attr1=12345, attr2=67890], 1=Outer[attr1=54321, attr2=9876]}]
Get as Array
You can then add a helper method to the Root class to get that as an array:
public Outer[] getOuterAsArray() {
if (this.outer == null)
return null;
if (this.outer.isEmpty())
return new Outer[0];
int maxKey = this.outer.keySet().stream().mapToInt(Integer::intValue).max().getAsInt();
Outer[] arr = new Outer[maxKey + 1];
this.outer.forEach((k, v) -> arr[k] = v);
return arr;
}
Test
System.out.println(Arrays.toString(root.getOuterAsArray()));
Output
[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]
Using Deserializer
However, it would likely be more useful if the conversion to array is done while parsing, so you need to write a JsonDeserializer and tell Gson about it using #JsonAdapter:
class Root {
#SerializedName("Outer")
#JsonAdapter(OuterArrayDeserializer.class)
public Outer[] outer;
#Override
public String toString() {
return "Root[outer=" + Arrays.toString(this.outer) + "]";
}
}
class OuterArrayDeserializer implements JsonDeserializer<Outer[]> {
#Override
public Outer[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// Parse JSON array normally
if (json.isJsonArray())
return context.deserialize(json, Outer[].class);
// Parse JSON object using names as array indexes
JsonObject obj = json.getAsJsonObject();
if (obj.size() == 0)
return new Outer[0];
int maxKey = obj.keySet().stream().mapToInt(Integer::parseInt).max().getAsInt();
Outer[] arr = new Outer[maxKey + 1];
for (Entry<String, JsonElement> e : obj.entrySet())
arr[Integer.parseInt(e.getKey())] = context.deserialize(e.getValue(), Outer.class);
return arr;
}
}
Same Outer class and test code as above.
Output
Root[outer=[Outer[attr1=12345, attr2=67890], Outer[attr1=54321, attr2=9876]]]
I'll asume your JsonObject is a POJO class such like:
public Inner[] outer;
If you want an array of objects you can change your code to:
Inner[] jo = gson.fromJson(json, Inner[].class);
Jackson – Marshall String to JsonNode will be useful in your case.with following pom:-
//POM FILE
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
//JAVA CODE
//read json file data to String
byte[] jsonData = Files.readAllBytes(Paths.get("employee.txt"));
//create ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();
//read JSON like DOM Parser
JsonNode rootNode = objectMapper.readTree(jsonData);
JsonNode idNode = rootNode.path("id");
System.out.println("id = "+idNode.asInt());
JsonNode phoneNosNode = rootNode.path("phoneNumbers");
Iterator<JsonNode> elements = phoneNosNode.elements();
while(elements.hasNext()){
JsonNode phone = elements.next();
System.out.println("Phone No = "+phone.asLong());
}
You can use the JsonNode class's method findParent findValue and findPath which reduce your code as compare to another parsing library.
Please refer below code
1.To get an array of Objects (outerArray)
2.You can extract a JsonArray (outerJsonArray) containing values of inner objects in Outer (in case keys aren't significant for further use)
String json = "{\"Outer\": { \"0\": { \"Attr1\": 12345, \"Attr2\": 67890 }, \"1\": { \"Attr1\": 54321, \"Attr2\": 09876 }}}";
Gson gson = new GsonBuilder().disableHtmlEscaping().setLenient().serializeNulls().create();
JsonObject jo = gson.fromJson(json, JsonObject.class);
JsonObject outer = jo.getAsJsonObject("Outer");
Object[] outerArray = outer.entrySet().toArray();
// outerArray: [0={"Attr1":12345,"Attr2":67890}, 1={"Attr1":54321,"Attr2":"09876"}]
JsonArray outerJsonArray = new JsonArray();
outer.keySet().stream().forEach(key -> {
outerJsonArray.add(outer.get(key));
});
//jsonArray=[{"Attr1":12345,"Attr2":67890},{"Attr1":54321,"Attr2":"09876"}]
System.out.println(outer);
System.out.println(outerJsonArray.isJsonArray() + " " + outerJsonArray);

Convert JSON into List of Object property (Java)

I have simple json which looks like this :
[
{
"id":"0",
"name":"Bob",
"place":"Colorado",
},
{
"id":"1",
"name":"John",
"place":"Chicago",
},
{
"id":"2",
"name":"Marry",
"place":"Miami",
}
]
What I want is using Java to create list of strings (List<String>) that contains all 'names'. I have some experience using Gson and I think about something like:
Gson gson = new Gson();
String[] stringArray= gson.fromJson(jsonString, " ".class);
The problem with this method is that I should create some POJO class which I didn`t in this case. Is it any way I can achieve it without creating separate class with this 'name' property ?
Using Jackson to parse, and Java 8 Streams API for extracting only the name field; the following may help you:
// Your string
jsonString = "[{ \"id\":\"0\", \"name\":\"Bob\", \"place\":\"Colorado\" }, { \"id\":\"1\", \"name\":\"John\", \"place\":\"Chicago\"}, { \"id\":\"2\", \"name\":\"Marry\", \"place\":\"Miami\" }]";
// using Jackson to parse
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.getTypeFactory();
List<MyInfo> myObjectList = objectMapper.readValue(jsonString, typeFactory.constructCollectionType(List.class, MyInfo.class));
// Java 8 Collections
List<String> nameList = myObjectList.stream().map(MyInfo::getName).collect(Collectors.toList());
Beware, it implies the usage of a MyInfo class representing your a Java class in which Json objects of yours would fit in.
You can use JSONArray to get value from key 'name'. Like this:
JSONArray jSONArray = new JSONArray(yourJson);
List<String> list = new ArrayList<>();
for (int i = 0; i < jSONArray.length(); i++) {
JSONObject object = (JSONObject) jSONArray.get(i);
String value = object.getString("name");
System.out.println(value);
list.add(value);
}
You may try the following code snippet,
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
List<String> ls = new ArrayList<String>();
JSONObject jsonObj = new JSONObject();
JSONArray jsonArr = new JSONArray();
JSONParser jsonParse = new JSONParser();
String str = "[{\"id\": \"0\",\"name\": \"Bob\",\"place\": \"Colorado\"},"
+ "{\"id\": \"1\",\"name\": \"John\",\"place\": \"Chicago\"},"
+ "{\"id\": \"2\",\"name\": \"Marry\",\"place\": \"Miami\"}]";
try {
jsonArr= (JSONArray) jsonParse.parse(str); //parsing the JSONArray
if(jsonArr!=null){
int arrayLength =jsonArr.size(); //size is 3 here
for(int i=0;i<arrayLength;i++){
jsonObj = (JSONObject) jsonParse.parse(jsonArr.get(i).toString());
ls.add(jsonObj.get("name").toString()); //as we need only value of name into the list
}
System.out.println(ls);
}
} catch (ParseException e) {
e.printStackTrace();
}catch(Exception e1){
e1.printStackTrace();
}
As you have array, use JSONArray and used jsonParse to avoid any parsing error.
I have used json-simple API to acheive the above.

Retrieve just one field from JSON string in Java

Is there a way to just one field from the JSON string? My code is as follows:
Object obj = parser.parse(resp);
System.out.println(obj);
JSONArray array = new JSONArray();
array.add(obj);
JSONObject obj2 = (JSONObject)array.get(0); //Getting NPE here
//Object obj3 = obj2.get("data");
System.out.println("Data: " + obj2.get("data"));
//System.out.println("Email: " + obj3.get("email_address"));
I'm using the following libraries
import org.json.simple.JSONObject;
import org.json.simple.JSONArray;
import org.json.simple.parser.ParseException;
import org.json.simple.parser.JSONParser;
From the response string resp, I just need data.email_address. I am unable to find a way to do it.
So if this is your input:
{
"data": {
"email_address": "example#example.com"
}
}
You first will need to make it a JSONObject:
JSONObject object = (JSONObject) new JSONParser().parse(json);
And then you can get data, another JSONObject:
JSONObject data = (JSONObject) object.get("data")
And from your data Object you can get email_address:
String email = data.get("email_address").toString();
If your input is an array of users, like this:
{
"users": [
{
"data": {
"email_address": "example#example.com"
}
},
{
"data": {
"email_address": "exapmle2#example2.com"
}
}
]
}
You can get it the same way:
JSONObject object = (JSONObject) new JSONParser().parse(json);
JSONArray users = (JSONArray) object.get("users");
JSONObject user0 = (JSONObject) users.get(0);
JSONObject user0data = (JSONObject) user0.get("data");
String email = user0data.get("email_address").toString();
First parse the whole JSON into an Object. Then get an array called users, from that array, get index 0. From that Object, get data, and then email_address
The other option is to use jsonpath.
Using the same Json blob as Lorant:
{
"data": {
"email_address": "example#example.com"
}
}
You would use the following expression.
$.data.email_address
Or if it was an array, simply.
$.users.[data].email_address
An online tool can be used to experiment and learn the syntax, but if you know xpath it should be somewhat familiar already.
import org.json.JSONObject;
JSONObject json = new JSONObject(record);
json.getString("fieldName"));

Create list of java objects from json

I have following json which i need to convert into list of java objects.
{
"model":[
{
"syscall_1":"execve",
"syscall_2":"brk"
},
{
"syscall_1":"brk",
"syscall_2":"access"
},
{
"syscall_1":"access",
"syscall_2":"mmap"
},
{
"syscall_1":"mmap",
"syscall_2":"access"
}
]
}
I am using gson and its TypeToken>(){}.getType() API ,however I am bit confused about how my objects should look corresponding to input json.
How can I use TypeToken in this scenario?
Another option (not using the type token, but still achieves what you want) would be to parse the entire json object, then access the model array like so:
import com.google.gson.Gson;
import java.util.List;
public class TestMe {
public static void main(String[] args) {
String jsonSt2 = "{\"model\":[{\"syscall_1\":\"execve\",\"syscall_2\":\"brk\"},{\"syscall_1\":\"brk\",\"syscall_2\":\"access\"},{\"syscall_1\":\"access\",\"syscall_2\":\"mmap\"},{\"syscall_1\":\"mmap\",\"syscall_2\":\"access\"}]}";
System.out.println("your json: " + jsonSt2);
ModelObject object = new Gson().fromJson(jsonSt2, ModelObject.class);
System.out.println("Created Model object, array size is " + object.model.size());
for (ModelItem mi : object.model) {
System.out.println(mi.syscall_1 + " " + mi.syscall_2);
}
}
}
class ModelObject {
List<ModelItem> model;
}
class ModelItem {
String syscall_1;
String syscall_2;
}
Output
Created Model object, array size is 4
execve brk
brk access
access mmap
mmap access
mmap access
If you can use org.json to parse and construct list objects, you can try this.
String jsonSt2 = "{\"model\":[{\"syscall_1\":\"execve\",\"syscall_2\":\"brk\"},{\"syscall_1\":\"brk\",\"syscall_2\":\"access\"},{\"syscall_1\":\"access\",\"syscall_2\":\"mmap\"},{\"syscall_1\":\"mmap\",\"syscall_2\":\"access\"}]}";
List<Model> models = new ArrayList<>();
JSONObject jsonModelObject = new org.json.JSONObject(jsonSt2);
Object modelObject = jsonModelObject.get("model");
if (modelObject instanceof JSONArray) {
JSONArray itemsArray =(JSONArray) modelObject;
for (int index = 0; index < itemsArray.length(); index++) {
Model model = new Model();
JSONObject modelItereative = (JSONObject) itemsArray.get(index);
model.setSyscall_1(modelItereative.getString("syscall_1"));
model.setSyscall_2(modelItereative.getString("syscall_1"));
models.add(model);
}
}else if(modelObject instanceof JSONObject){
Model model = new Model();
JSONObject modelItereative = (JSONObject) modelObject;
model.setSyscall_1(modelItereative.getString("syscall_1"));
model.setSyscall_2(modelItereative.getString("syscall_1"));
models.add(model);
}
for(Model d22:models){
System.out.println(d22.getSyscall_1() + " " + d22.getSyscall_2());
}

Parsing JSON array

I'm using GSON for parsing JSON response.
Unfortunately the WebApi on the server has quite untypical JSON objects.
I need to parse Attachments array from this JSON (there can be more attachments):
{"htmlMessage":"text","Attachments":{"8216096_0":{"content":null,"filename":"plk.jpg","contentType":"image/jpeg","contentDisposition":"attachment","size":86070}}}
Where 8216096_0 is attachments id.
I can't do it with Gson (or I don't know how) so I'm trying to do it with JSONObjects:
// parse attachments
JSONObject attachmentsJson = result.getJSONObject("Attachments");
Then I have one JSONObject with an array of attachments, but I don't know how to get them to the ArrayList from JSONObject because the key value isn't static but generated id..
Thank you
//EDIT:
Thanks to all guys for helping! My final solution looks like this especially thanks to #Jessie A. Morris and his final answer!
List<AttachmentModel> attachmentsList = new ArrayList<AttachmentModel>();
for( Map.Entry<String, JsonElement> attachment : attachments.entrySet()) {
AttachmentModel attachmentModel = new AttachmentModel();
attachmentModel = gson.fromJson(attachment.getValue().getAsJsonObject().toString(), AttachmentModel.class);;
attachmentModel.setmUid(attachment.getKey());
attachmentsList.add(attachmentModel);
}
Okay, I've changed my example a little bit and am certain that this does work correctly (I just tested it):
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by jessie on 14-07-09.
*/
public class TestGson {
private static String JSON = "{\"htmlMessage\":\"text\",\"Attachments\":{\"8216096_0\":{\"content\":null,\"filename\":\"plk.jpg\",\"contentType\":\"image/jpeg\",\"contentDisposition\":\"attachment\",\"size\":86070}}}\n";
public static void main(String[] args) {
JsonObject json = new JsonParser().parse(JSON).getAsJsonObject();
JsonObject attachments = json.getAsJsonObject("Attachments");
List<JsonObject> attachmentsList = new ArrayList<JsonObject>();
for( Map.Entry<String, JsonElement> attachment : attachments.entrySet()) {
attachmentsList.add(attachment.getValue().getAsJsonObject());
}
System.out.println("attachmentsList at the end? " + attachmentsList);
}
}
I'm not completely sure if this really works:
final Map<String,JSONObject> attachmentsJson = (Map<String,JSONObject>) jsonArray.getJSONObject("Attachments");
for(String attachmentId : attachmentsJson.keySet()) {
final JSONObject attachmentJson = attachmentsJson.get(attachmentId);
}
The "Attachments" obj in your example is not an array.
Json arrays are denoted by [....].
"Attachments" is a Json object holding an inner object called "8216096_0".
so to get the inner values do as follows:
JSONObject attachmentsJson = result.getJSONObject("Attachments");
JSONObject inner = attachmentsJson.getJSONObject("8216096_0");
// and interrogate the inner obj:
String content = inner.getString("content");
String filename = inner.getString("filename");
Finally, and for example sake, I will add the code for processing a (real) Json array:
{"htmlMessage":"text",
"Attachments":[{"8216096_0":{"content":null,"filename":"plk.jpg","contentType":"image/jpeg",
"contentDisposition":"attachment","size":86070}},
{"8216096_1":{"content":null,"filename":"plk.jpg","contentType":"image/jpeg",
"contentDisposition":"attachment","size":86070}},
]
}
It will go like this:
JSONArray attachmentsJson = result.getJSONObject("Attachments");
int len = attachmentsJson.length();
for (int i = 0; i < len; i++) {
JSONObject elem = attachmentsJson.getJSONObject(i); // <------ get array element
JSONObject inner = elem.getJSONObject("8216096_0");
// and interrogate the inner obj:
String content = inner.getString("content");
String filename = inner.getString("filename");
}
..Or similar, depending on your Json's exact format.

Categories

Resources