Parsing nested JSON in Java - java

I have a weird JSON which looks like this
[
[
{
"id": "1",
"clientId": "user"
},
{
"id": "2",
"clientId": "user"
}
],
[
{
"Status": "NotCompleted",
"StatusId": 0
},
{
"Status": "Importing",
"StatusId": 10
}
]
]
I am trying to parse it with Gson or JsonParser.
Classes look like this
public class Event {
public String id;
public String clientId;
}
public class Status {
public String Status;
public String StatusId;
}
public class AllEvents {
public Event[] events;
public Status[] statuses;
}
But when I am trying to parse it with Gson (e.g)
AllEvents[] r = new Gson().fromJson(response, AllEvents[].class);
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was BEGIN_ARRAY at line 1 column 6 path $[0]
Could you please help me out with parsing this kind of model? Cannot find what I am doing wrong in this case.
Thanks in advance

To solve such a problem there is two approaches:
First Approach:
Change your JSON file content(allEvents) to :
[
{
"events": [
{
"id": "1",
"clientId": "user"
},
{
"id": "2",
"clientId": "user"
}
],
"statuses": [
{
"Status": "NotCompleted",
"StatusId": 0
},
{
"Status": "Importing",
"StatusId": 10
}
]
}
]
and after that, your code will work perfectly.
Second Approach:
you need to code according to match above JSON structure:
Please find below the code which will help you.
Gson gson = new Gson();
Object[] r = gson.fromJson(loadDataAsString(), Object[].class);
AllEvents allEvents = new AllEvents();
//if your json structure position is fixed the do this commented code
//allEvents.events = gson.fromJson(gson.toJson(r[0]), Event[].class); //if your json Event structure position is fixed at 0 index
//allEvents.statuses = gson.fromJson(gson.toJson(r[1]), Status[].class); //if your json Status structure position is fixed at 1 index
//if your json structure position is not fixed the do below code
allEvents.events = Arrays.stream(r)
.flatMap(x -> Arrays.stream(gson.fromJson(gson.toJson(x), Event[].class)))
.filter(y -> y.id != null).toArray(Event[]::new);//id as primary key
allEvents.statuses = Arrays.stream(r)
.flatMap(x -> Arrays.stream(gson.fromJson(gson.toJson(x), Status[].class)))
.filter(y -> y.Status != null).toArray(Status[]::new);//Status as primary key
System.out.println(gson.toJson(allEvents));//{"events":[{"id":"1","clientId":"user"},{"id":"2","clientId":"user"}],"statuses":[{"Status":"NotCompleted","StatusId":"0.0"},{"Status":"Importing","StatusId":"10.0"}]}

Use JsonReader instead. So if you know you json starts with [ and ends with ] use read with beginArray. Your in is an InputStream, it can be a file, socket stream or string stream.
JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8"));
List<YourMessage> messages = new ArrayList<YourMessage>();
reader.beginArray();
while (reader.hasNext()) {
messages.add (do something with reader);//<-- that is pseudo code
}
reader.endArray();
return messages;
For more detail check this link https://www.javadoc.io/doc/com.google.code.gson/gson/2.8.0/com/google/gson/stream/JsonReader.html

Solved issue in this way:
org.json.JSONArray allEvents = new org.json.JSONArray(response.getBodyAsString());
As a result I received JSONArray with 2 elements. Then extracted needed one through
allEvents.getJSONArray(0)
And then mapped in previous way with jackson ObjectMapper.
Thx for replies!

Related

The sum of several items in a json

I have a JSON source with more empty_slots elements (in the example exist below only one, but in the reality exist more stations with empty_slots). How can I sum the values from empty_slots and return as double? Thanks!
JAVA
public static double getValueFromJSONString(String jString) throws JSONException
{
JSONObject json = new JSONObject(jString);
return json.getJSONObject("empty_bikes").getDouble(jString);
}
JSON
{"network": {
"company": [
"Gewista Werbegesellschaft m.b.H"
],
"id": "citybike-wien",
"location": {
"city": "Wien",
},
"stations": [
{
"empty_slots": 3,
"extra": {
"slots": "26",
},
"free_bikes": 23
}]}
Checkout JsonPath. Below code is not tested but should work with RestAssured dependency - https://github.com/rest-assured/rest-assured
JsonPath jsonPath = new JsonPath(jsonString);
List<Integer> companyEntityIds = jsonPath.getList("network.stations.empty_slots");
Once you have the array you can just use a stream or whatever to add these up.

Create a JSON without a key

We wanted to create a JSON structure as below in Java
{
[
{
"key": "ABC001",
"value": true
},
{
"key": "ABD12",
"value": false
},
{
"key": "ABC002",
"value": true
},
]
}
To implement this we created a class and had a list private property inside it.
But that is creating a key values
class Response{
private List<Property> values;
// setter getter for this private property
}
The output for this is
{
values : [
{
"key": "ABC001",
"value": true
},
......
]
Is there a way we create the array without the key and inside the { }?
Unfortunately, what you're trying to build is not a valid json.
You can try to validate it here.
With this "json", for example, it would be impossible to read the array, because it has no key.
{
"foo_key" : "bar",
[
{
"key": "ABC001",
"value": true
},
{
"key": "ABD12",
"value": false
},
{
"key": "ABC002",
"value": true
},
]
}
Parsing a json like this one, you could get "bar" because it has a key ("foo_key"), but how could you get the array?
The code you're using is already correct for a valid json.
So, for some reason you want an invalid json, which is an array contained between {}s. Here's how you can do it (I'll assume you use google-gson to make and parse jsons, since you didn't include your code):
// example of the creation of the list
List<Property> values = new ArrayList<>();
values.add(new Property("ABC001", true));
values.add(new Property("ABD12", false));
values.add(new Property("ABC002", true));
//
Gson gson = new Gson();
String json = gson.toJson(values, new TypeToken<List<Property>>() {}.getType());
json = "{" + json + "}";// gotta do what you gotta do...

Reading value of nested key in JSON with Java (Jackson)

I'm a new Java programmer coming from a background in Python. I have weather data that's being collected/returned as a JSON with nested keys in it, and I don't understand how pull the values out in this situation. I'm sure this question has been asked before, but I swear I've Googled a great deal and I can't seem to find an answer. Right now I'm using json-simple, but I tried switching to Jackson and still couldn't figure out how to do this. Since Jackson/Gson seem to be the most used libraries, I'd would love to see an example using one of those libraries. Below is a sample of the data, followed by the code I've written so far.
{
"response": {
"features": {
"history": 1
}
},
"history": {
"date": {
"pretty": "April 13, 2010",
"year": "2010",
"mon": "04",
"mday": "13",
"hour": "12",
"min": "00",
"tzname": "America/Los_Angeles"
},
...
}
}
Main function
public class Tester {
public static void main(String args[]) throws MalformedURLException, IOException, ParseException {
WundergroundAPI wu = new WundergroundAPI("*******60fedd095");
JSONObject json = wu.historical("San_Francisco", "CA", "20100413");
System.out.println(json.toString());
System.out.println();
//This only returns 1 level. Further .get() calls throw an exception
System.out.println(json.get("history"));
}
}
The function 'historical' calls another function that returns a JSONObject
public static JSONObject readJsonFromUrl(URL url) throws MalformedURLException, IOException, ParseException {
InputStream inputStream = url.openStream();
try {
JSONParser parser = new JSONParser();
BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String jsonText = readAll(buffReader);
JSONObject json = (JSONObject) parser.parse(jsonText);
return json;
} finally {
inputStream.close();
}
}
With Jackson's tree model (JsonNode), you have both "literal" accessor methods ('get'), which returns null for missing value, and "safe" accessors ('path'), which allow you to traverse "missing" nodes. So, for example:
JsonNode root = mapper.readTree(inputSource);
int h = root.path("response").path("history").getValueAsInt();
which would return the value at given path, or, if path is missing, 0 (default value)
But more conveniently, you can just use JSON pointer expression:
int h = root.at("/response/history").getValueAsInt();
There are other ways too, and often it is more convenient to actually model your structure as Plain Old Java Object (POJO).
Your content could fit something like:
public class Wrapper {
public Response response;
}
public class Response {
public Map<String,Integer> features; // or maybe Map<String,Object>
public List<HistoryItem> history;
}
public class HistoryItem {
public MyDate date; // or just Map<String,String>
// ... and so forth
}
and if so, you would traverse resulting objects just like any Java objects.
Use Jsonpath
Integer h = JsonPath.parse(json).read("$.response.repository.history", Integer.class);
Check out Jackson's ObjectMapper. You can create a class to model your JSON then use ObjectMapper's readValue method to 'deserialize' your JSON String into an instance of your model class. And vice-versa.
Try jpath API. It's xpath equivalent for JSON Data. You can read data by providing the jpath which will traverse the JSON data and return the requested value.
This Java class is the implementation as well as it has example codes on how to call the APIs.
https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java
Readme -
https://github.com/satyapaul/jpath/blob/master/README.md
Example:
JSON Data:
{
"data": [{
"id": "13652355666_10154605514815667",
"uid": "442637379090660",
"userName": "fanffair",
"userFullName": "fanffair",
"userAction": "recommends",
"pageid": "usatoday",
"fanPageName": "USA TODAY",
"description": "A missing Indonesian man was found inside a massive python on the island of Sulawesi, according to local authorities and news reports. ",
"catid": "NewsAndMedia",
"type": "link",
"name": "Indonesian man swallowed whole by python",
"picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
"full_picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
"message": "Akbar Salubiro was reported missing after he failed to return from harvesting palm oil.",
"link": "http:\/\/www.usatoday.com\/story\/news\/nation-now\/2017\/03\/29\/missing-indonesian-man-swallowed-whole-reticulated-python\/99771300\/",
"source": "",
"likes": {
"summary": {
"total_count": "500"
}
},
"comments": {
"summary": {
"total_count": "61"
}
},
"shares": {
"count": "4"
}
}]
}
Code snippet:
String jPath = "/data[Array][1]/likes[Object]/summary[Object]/total_count[String]";
String value = JSONDataReader.getStringValue(jPath, jsonData);

JSON different objects in an array

At the moment i'm trying to understand json and how it works.
But i have a problem with an array of objects.
all objects in the array have a key called "value" (i know it's weird, it's not my code) what also is an object.
And now to the problem: This object called "value" has always different key-values.
So i dont now how i can parse the json code to java object code, when it differ, every time.
Here some examples:
First object of the array:
"value":
{
"local":
[
"English", "Deutsch", Espanol"
],
"english":
[
"English", "Deutsch", Espanol"
],
},
Second object(now a string, not object) of the array:
"value" : "",
Third object of the array:
"value" : {},
...
Maybe I'm doing the parsing wrong.
First I have created the beans classes in java for the json code and then I'm using the automatic parser of google. (gson)
It works when only one of the examples above is inside the json code. (it should not differ, like changing from string to object...)
Gson gson = new Gson();
Output output = gson.fromJson(json, Output.class);
Output is the main class for the json stuff.
I have found out that maybe while parsing I could check a value called "id" first, and from that I could create another beans class with the right variables ...
Thats the code i need to parse to java objects and how do you do that??
The problem is the key called "value", because its always different.
With my method of using the google parser "gson" it wont work, because i'm getting exception that its an string but i was waiting for an object...
{
"status":"success",
"data":{
"panel":{
"title":{
"label":{ "local":"Tote Selection", "english":"Tote Selection" },
"image":"public/img/pick.jpg", "type":"default"
},
"isFirst":false, // currently not used
"isLast":false, // currently not used
"ownCount":0, // currently not used
"panelsCount":0, // currently not used
"elements":[
{
"type":"text",
"id":"1", "value":{ "local":"Scan next order tote",
"english":"Scan next order tote" },
"label":{ "local":"", "english":"" }, "color":"000000",
"fontsize":18, "fontstyle":"flat", "alignment":"left",
"rows":"undefined", "bgcolor":"", "isFocus":false
},
{
"type":"text",
"id":"4", "value":{ "local":"Scan tote: ", "english":"Scan tote: " },
"label":{ "local":"", "english":"" }, "color":"000000", "fontsize":20,
"fontstyle":"strong", "alignment":"left", "rows":"undefined",
"bgcolor":"", "isFocus":false
},
{
"type":"input",
"id":"6", "value":"", "label":{ "local":"", "english":"" },
"color":"000000", "fontsize":24, "fontstyle":"flat", "alignment":"left",
"rows":"undefined", "isFocus":true
},
{
"type":"button",
"id":"1", "value":{ "local":"", "english":"" },
"label":{ "local":"Menu", "english":"Menu" }, "color":"000000",
"fontsize":14, "fontstyle":"strong", "alignment":"left",
"rows":"undefined", "isFocus":false
},
{
"type":"button",
"id":"4", "value":{ "local":"", "english":"" },
"label":{ "local":"Enter", "english":"Enter" }, "color":"000000",
"fontsize":14, "fontstyle":"strong", "alignment":"right",18
"rows":"undefined", "isFocus":false
}
]
},
"authToken":"0fdd440a-619f-4936-ab74-d189accb5bd9",
"routing":{
"controller":"panel",
"action":"process",
"workflowId":"singlepicking",
"taskId":"orderSelection"
}
}
}
Thank you for your help!
it looks a little bit different but your answer helped me! Thx
JsonParser parser = new JsonParser();
JsonObject obj = parser.parse(br).getAsJsonObject();
//now getting all the json values
String status = obj.get("status").getAsString();
JsonObject data = obj.getAsJsonObject("data");
String authToken = data.get("authToken").getAsString();
JsonObject routing = data.getAsJsonObject("routing");
String controller = routing.get("controller").getAsString();
String action = routing.get("action").getAsString();
String workflowId = routing.get("taskId").getAsString();
If I understood ur question properly u can retrieve the values of the JSONArray as below
for (int i = 0; i < JArray.length(); i++) {
print(JArray.getJSONObject(i).tostring())
}
So if i am right u are getting the JSON from a String First?? so please try below first store the String in JSONObject as JSONObject obj = new JSONObject(str);//str is the string that u are getting
to get the valueenglish that are in data-panel-tittle-label is
String englishinLable=obj .getJSONObject("data").getJSONObject("panel").getJSONObject("title").getJSONObject("label").optString("english")

Unable to get specific data from a JSON object

I am trying to extract specific data from a json response using org.json.JSONObject library
Heres is my json response :
{
"facets": {
"application": [
{
"name": "38",
"distribution": 1
}
],
"node": [
{
"name": "frstlwardu03_05",
"distribution": 1
}
],
"area": [
{
"name": "x",
"distribution": 1
}
],
"company": [
{
"name": "war001",
"distribution": 1
}
]
},
"duObjects": [
{
"id": "TASK|TSK(ZRM760J)(000)(ZRM760JU00)(000)|ZSRPSRM000",
"name": "TSK(ZRM760J)(000)(ZRM760JU00)(000)",
"mu": "ZSRPSRM000",
"label": "",
"session": "ZRM760J|000",
"sessionLabel": "SAP SRM Achats frais generaux execution",
"uprocHeader": "ZRM760JU00|000",
"uprocHeaderLabel": "Header for SRM760J",
"uprocHeaderType": "CL_INT",
"domain": "M",
"domainLabel": "",
"application": "38",
"applicationLabel": "magasin",
"highlightResult": {
"name": "name",
"word": "TSK"
}
}
],
"totalCount": 1,
"pageSize": 10,
"pageCurrent": 1,
"pageNb": 1
}
Here is the method I used to convert the URL call to a jsonobject :
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException
{
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-
8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
}
When I call this method I am able to get the data in teh Duobject :
public static void main(String[] args) throws IOException, JSONException {
JSONObject json = readJsonFromUrl("http://frstmwarwebsrv.orsyptst.com:9000/duobject?
searchString=TSK(ZRM760J)(000)(ZRM760JU00)
(000)&filterchecks=nameJob,nameWF,nameSWF,application,domain&p.index=0&p.size=10");
System.out.println(json.getJSONArray("duObjects"));
}
Is there anyway I can extract only the name field of the DuObjects?
You can use
System.out.println(json.getJSONArray("duObjects").getJSONObject(0).getString("name"));
to get the name.
1 : your complete response is a JSON OBJECT
2 : if any element is written like
"some key name " : { " some value " }
this is a JSON Object
3 : if any element is writen like
"some key name " : " some value "
this is value inside you json object which you can get by
jsonObject.getString("key name")
4 : if any element is writen like
"some key name " : [ " some value " ]
then this is a JSON Array and you have to take it in to a JSON ARRAY and then traverse its elements by
jsonObject.getJSONARRAY("key name for JSON ARRAY IN RESPONSE ")
and then you can traverse the elements of the JSON ARRAY by
`jsonArrayObj.get(0);`
You can use Jackson libraries to covert to java. Jackson api provides annotation level and it automatically converts json to pojo object and object to json vice versa . refer this link. you can get good idea about this
http://wiki.fasterxml.com/JacksonSampleSimplePojoMapper
http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson/

Categories

Resources