Java - Parsing JSON Response - Content is either String or JSONObject - java

I am facing a typical scenario while parsing JSON Response for one of the Service calls.
The content for one of the attributes (from below example, consider "name" as a attribute) coming as either String or JSONObject.
How to handle these kind of scenarios through code. Also, please consider that json content need not be consistent with same set of attributes.
Example:
String Response
{"name":"Adam"}
JSON Response
{"name":{"FirstName":"Adam", "MiddleName":"Don"} }
OR
{"name":{"FirstName":"Adam", "LastName":"Don"} }
OR
{"name":{"MiddleName":"Adam", "LastName":"Don"} }

You can ask the root JSONObject with the method optJSONObject(name) to return a JSONObject for the given name if it exists and is an JsonObject. Otherwise you can also test with optString(name) for a String.
So something like:
JSONObject root = new JSONObject(... data from server ... );
JSONObject obj = root.optJSONObject("name");
if (obj != null) {
// Do something with the object
} else {
String name = root.getString("name");
// Do something with the string
}

Parse your response JSON as a JSONObject, then get another JSONObject for the "name" key, if it throws a JSONException then your object is probably a String in with case you can call get String for the "name" key in your catch block.
String name = "";
JSONObject serverJSON = new JSONObject(YOUR_JSON_RESPONSE_STRING_FROM_SERVER);
try {
JSONObject nameObject = serverJSON.getJSONObject("name");
if (nameObject.has("first_name")) {
name = nameObject.getString("first_name") + " ";
}
if (nameObject.has("middle_name")) {
name += nameObject.getString("middle_name") + " ";
}
if (nameObject.has("last_name")) {
name += nameObject.getString("last_name");
}
name = name.trim();
} catch (JSONException e) {
// Probably a String, try again...
try {
name = serverJSON.getString("name");
catch (JSONException e) {
// Not a String or a JSONObject... figure out what's wrong...
e.printStackTrace();
}
}
I would really recommend though, that if you have any control of the server that you make sure that the name key choose one type and sticks to it; a JSONObject... You would be able to use the has(String key) member function in if statements to properly find all of your data without knowing what existed at runtime...
EDIT: Thought of a different idea... Parse the String to the first colon and see if the next non-whitespace character is a quotation mark, if it is, then your key belongs to a String, if it is a curly brace then it's a JSONObject. (If neither, then you have an error, because you aren't expecting an array or number or null or anything else...)
boolean jsonIsString = true;
String searchString = json.substring(json.indexOf(":")).trim();
if ("{".equals(searchString.charAt(0)) {
jsonIsString = false;
}

Tonity's solution is good. You can also use this solution.
In my solution, there will be no any Exception fired until JSON is wrong. What I am doing is following.
Search for number of ":" in string.
If it returns 1, then we sure that there is "name" value.
Otherwise, we need to check, whether there is "FirstName","MiddleName" or "LastName" exist in string or not.
Just go through this snippet and you will find solution for your problem.
// String str = "{\"name\":\"chintan\"}";
String str = "{\"name\":{\"FirstName\":\"Chintan\",\"LastName\":\"Rathod\"}}";
try {
//we will check how many ":" are there in string, if it is one, then
// we are going to get "name" field.
if ((str.split(":").length - 1) == 1)
{
Log.d("Home", "1");
JSONObject json = new JSONObject(str);
Log.d("Home", "Name : " + json.get("name"));
}
else
{
Log.d("Home", "more then 2");
JSONObject jName = new JSONObject(str);
JSONObject jTemp = jName.getJSONObject("name");
if (jTemp.toString().contains("FirstName"))
Log.d("Home", "FirstName :" + jTemp.getString("FirstName"));
if (jTemp.toString().contains("MiddleName"))
Log.d("Home","MiddleName :" +jTemp.getString("MiddleName"));
if (jTemp.toString().contains("LastName"))
Log.d("Home", "LastName :" + jTemp.getString("LastName"));
}
} catch (JSONException e) {
e.printStackTrace();
}
Output
08-06 11:52:34.060: D/Home(1439): more then 2
08-06 11:52:34.060: D/Home(1439): FirstName :Chintan
08-06 11:52:34.070: D/Home(1439): LastName :Rathod

I faced a problem like this as well. I didn't want to parse the JSON manually. Do this if firstName exists otherwise do that. I didn't want to mess up my structure because I only define java object and my client handles the parsing. So, I came up with following:
#Getter
#Setter
#ToString
class Response {
private Name name;
#Getter
#Setter
#NoArgsConstructor
#ToString
public static class Name {
private String name;
private String firstName;
private String middleName;
private String lastName;
public Name(String name) {
this.name = name;
}
}
}
Then, parse the json;
ObjectMapper objectMapper = new ObjectMapper();
Response response = objectMapper.readValue(json, Response.class);
Now, string response and JSON response can be parsed with the same class.

Related

Convert JSON to different looking CSV in Java

I need to write a code which would convert JSON file to CSV. The problem is in a format that the CSV file should look like.
Input json:
{
"strings":{
"1level1":{
"1level2":{
"1label1":"1value1",
"1label2":"1value2"
}
},
"2level1":{
"2level2":{
"2level3":{
"2label1":"2value1"
},
"2label2":"2value2"
}
}
}
}
And this is expected csv file for this json:
Keys,Default
1level1.1level2.1label1,1value1
1level1.1level2.1label2,1value2
2level1.2level2.2level3.2label1,2value1
2level1.2level2.2label2,2value2
I was trying to go through JSON file using recursion but this didn't work for me because of rewriting JSON object on each iteration and code was working only till the first value. Are there any suggestions about how can it be done?
Note: have tried to use different JSON libraries, so for now can be used any of them
UPDATE #1:
Non-working code example I was trying to use to go through JSON tree:
public static void jsonToCsv() throws JSONException {
InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
JSONTokener jsonTokener = new JSONTokener(is);
JSONObject jsonObject = new JSONObject(jsonTokener);
stepInto(jsonObject);
}
private static void stepInto(JSONObject jsonObject) {
JSONObject object = jsonObject;
try {
Set < String > keySet = object.keySet();
for (String key: keySet) {
object = object.getJSONObject(key);
stepInto(object);
}
} catch (JSONException e) {
Set < String > keySet = object.keySet();
for (String key: keySet) {
System.out.println(object.get(key));
}
e.printStackTrace();
}
}
UPDATE #2:
Another issue is that I will never know the names of the JSON object and count of child objects (update JSON and CSV examples as well to make the image more clear). All that is known, that it will always start with strings object.
Library used:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
So found a solution by myself:
public static void jsonToCsv() throws JSONException, IOException {
InputStream is = MainClass.class.getResourceAsStream("/fromJson.json");
JSONTokener jsonTokener = new JSONTokener(is);
JSONObject jsonObject = new JSONObject(jsonTokener).getJSONObject("strings");
builder = new StringBuilder();
while (!jsonObject.isEmpty()) {
stepInto(jsonObject);
}
String[] lines = builder.toString().split("\n"); // builder lines are in reverse order from expected so this array is used to reverse them
FileWriter csvWriter = new FileWriter("src/main/resources/toCsv.csv");
csvWriter.append("Keys,Default (en_US)\n");
for (int i = lines.length - 1; i >= 0; i--) {
csvWriter.append(lines[i]).append("\n");
}
csvWriter.flush();
csvWriter.close();
}
private static void stepInto(JSONObject jsonObject) {
for (String key: jsonObject.keySet()) {
Object object = jsonObject.get(key);
if (object instanceof JSONObject) {
builder.append(key).append(".");
stepInto(jsonObject.getJSONObject(key));
} else {
builder.append(key).append(",").append(object).append("\n");
jsonObject.remove(key);
break;
}
if (jsonObject.getJSONObject(key).isEmpty()) {
jsonObject.remove(key);
}
break;
}
}
I think you just missed keeping track of your result, otherwise it looks good.
Let's say your result is a simple string. Then you have to concatenate all keys while traversing the json object until you reach a primitive value (like a number or a string).
(I am writing this out of my head, so please forgive me for incorrect syntax)
private static String stepInto(JSONObject jsonObject) { // we change "void" to "String" so we can record the results of each recursive "stepInto" call
//JSONObject object = jsonObject; // we don't need that. Both variables are the same object
String result ="";
try {
for (String key: jsonObject.keySet()) { // shorter version
Object object = jsonObject.get(key); // Attention! we get a simple Java Object
if(object instanceof JSONObject){
result+= key+"."+stepInto(jsonObject.getJSONObject(key)); // the recursive call, returning all keys concatenated to "level1.level2.level3" until we reach a primitive value
}
if(object instanceof JSONArray){
result+= key+", "+ ... // notice how we use the csv separator (comma) here, because we reached a value. For you to decide how you want to represent arrays
}
result+= key +", "+ object +"\n"; // here I am not sure. It may well be that you need to check if object is a String an Integer, Float or anything.
}
} catch (JSONException e) {
for (String key: jsonObject.keySet()) {
System.out.println(object.get(key));
}
e.printStackTrace();
result+= "\n"; // I added this fallback so your program can terminate even when an error occurs.
}
return result; // sorry, I forgot to accumulate all results and return them. So now we have only one actual "return" statement that will terminate the call and return all results.
}
As you can see, I didn't change much of your original method. The only difference is that now we keep track of the keys ("level1.level2...") for each recursive call.
EDIT
I added a +"\n"; so everytime we reach a value so we can terminate that "line".
AND more importantly, instead of returning everytime, I add the result of each call to a string, so we continue looping over the keys and concatenate all results. Each call of the method will return only once all keys are looped over. (sorry that missed that)
In your calling method you could print out the result, something like that:
JSONObject jsonObject = new JSONObject(jsonTokener);
String result = stepInto(jsonObject);
System.out.println(result);

Obtain specific part of a string with JSON Format java

I have a question on how would be the best way to get the information from a string but that has JSON format.
{
"internal_id":"1234",
"moreInformation":"Failed authentication for user."
}
In this case, I want to get the value of "internal_id" and I already did, with subtring, lastIndexOf and indexOf
public static String returnInternalCode(String json){
String internalCode = json.substring(json.lastIndexOf("\"internal_id\":\"") + "\"internal_id\":\"".length(), json.length() - 1);
if (json.lastIndexOf("\"internal_id\":\"") == -1) return null;
return internalCode.substring(0, internalCode.indexOf("\""));
}
I also tried several JSONs with order changes that don't have the data and it also worked. I leave the full class of tests I did:
public class Test {
public static void main(String[] args) {
// Original JSON
String json = "{\"internal_id\":\"999999\",\"moreInformation\":\"Failed authentication for user, 1 authentication attempt remaining.\"}";
// Other JSON order
String json2 = "{\"moreInformation\":\"Failed authentication for user. Invalid response.\", \"moreInformation2\":\"Failed authentication for user. \", \"internal_id\":\"45678\"}";
// JSON without the internal_id
String json3 = "{\"moreInformation\":\"Failed authentication for user. Invalid response.\"}";
// JSON without moreInformation
String json4 = "{\"internal_id\":\"999999\"}";
System.out.println("JSON: ".concat(json4));
System.out.println("internalId: " + returnInternalId(json4));
System.out.println("moreInformation: " + returnMoreInformation(json4));
}
public static String returnInternalId(String json){
String internalCode = json.substring(json.lastIndexOf("\"internal_id\":\"") + "\"internal_id\":\"".length(), json.length());
if (json.lastIndexOf("\"internal_id\":\"") == -1) return null;
return internalCode.substring(0, internalCode.indexOf("\""));
}
public static String returnMoreInformation(String json){
String moreInformation = (json.substring(json.lastIndexOf("\"moreInformation\":\"") + "\"moreInformation\":\"".length(), json.length()));
if (json.lastIndexOf("\"moreInformation\":\"") == -1) return null;
return moreInformation.substring(0, moreInformation.indexOf("\""));
}
}
I would like to know if there are better ways to do what I did, such as with StringBuilder or StringBuffer and also to find out which way uses less memory or is faster to run, how do I know that? How long does it take to execute a method?
Thank you very much!
You can extract the values this way; Using Simple-json library
JSONObject jobj = (JSONObject) parser.parse(yourJsonString); // Pass the Json formatted String
String internal_id = (String) jobj.get("internal_id"); // Extract the value from your key
System.out.println(internal_id); // 1234

Convert string of valid JSON to JSON object in Java, so I can index into it

I have this string:
[{"row 0":[{},{},{},{},{},{},{},{}]},{"row 1":[{},{},{},{},{},{},{},{}]},{"row 2":[{},{},{},{},{},{},{},{}]},{"row 3":[{},{},{},{},{},{},{},{}]},{"row 4":[{"column 0":"WhitePawn"},{},{},{},{},{},{},{}]},{"row 5":[{},{},{},{},{},{},{},{}]},{"row 6":[{},{},{},{},{},{},{},{}]},{"row 7":[{},{},{},{},{},{},{},{}]}]
^ it's currently a String, let's call it string.
I'm trying to convert it into JSON like so:
new JSONObject(string);
but it isn't working. How to do this in Java?
Code looks like so:
private void parseMessageRedrawBoard(String message) {
Log.d("0000: ", message);
String trimmed = message.substring(message.indexOf("["));
Log.d("1111: ", trimmed);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(trimmed);
Log.d("maybe worked...", "~");
} catch (Exception e) {
Log.d("dammit: ", e.getMessage());
}
}
You are trimming the string and turning it into an invalid JSON.
Your JSON starts with a "[" that indicates it is an array. If it starts with "{" you can assume that is an object.
So, as your JSON is an array, you can parse this exact content you mentioned with:
JSONArray jsonArray = new JSONArray(string);
And access the elements like in a List:
jsonArray.get(0);

Parse Json In Java How to read Inner Value

Very New with Java Development Parsing JSON in JAVA Here is my Code.
package com.zenga.control;
import java.io.BufferedReader;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
public class Start {
public String readUrl(String urlString) {
String jsonString = null;
try {
HttpClient client = new HttpClient();
GetMethod get = new GetMethod(urlString);
client.executeMethod(get);
jsonString = get.getResponseBodyAsString();
}catch(Exception e) {
}
return jsonString;
}
public void getAddAsBeanObject() {
try {
String jsonString = new Start().readUrl("http://myDomain/JsonZ.json");
JSONObject obj = (JSONObject) JSONSerializer.toJSON(jsonString);
System.out.println(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Start().getAddAsBeanObject();
}
}
As I successfully Read Value in JSONObject and it also showing all JSON String on console But How can i Get Value For ID and UID and DURATION ?
Here The JSONString the i read in System.out.println(obj);
{
"Demo": {
"CONTENT": [
{
"ID": " 283 ",
"UID": " 87897bc8-ae9b-11e1-bdcf-123141042154 ",
"DURATION": "Full"
},
{
"ID": " 283 ",
"UID": " 87897bc8-ae9b-11e1-bdcf-123141042154 ",
"DURATION": "Full"
}
]
}
}
Following code can be used to iterate the JSON objects inside the JSON array 'CONTENT', using .get(java.lang.String) as documented, to pull the value out of the JSONObject.
I have only demonstrated how to get the ID but the same logic applies to the other values.
JSONObject obj = (JSONObject) JSONSerializer.toJSON(jsonString);
JSONArray content = obj.getJSONObject("Demo").getJSONArray("CONTENT");
java.util.Iterator<?> iterator = content.iterator();
while (iterator.hasNext()) {
JSONObject o = (JSONObject) iterator.next();
System.out.println(o);
System.out.println(o.get("ID"));
// etc...
}
Following is a sample code to reach the array`s inner objects specific to pattern you have provided.
String str = "{"+
"\"Demo\": {"+
"\"CONTENT\": ["+
" {"+
"\"ID\": \" 283 \","+
"\"UID\": \" 87897bc8-ae9b-11e1-bdcf-123141042154 \","+
"\"DURATION\": \"Full\""+
" },"+
"{"+
"\"ID\": \" 283 \","+
"\"UID\": \" 87897bc8-ae9b-11e1-bdcf-123141042154 \","+
"\"DURATION\": \"Full\""+
" }"+
"]"+
"}"+
"}";
try {
JSONObject jsr = new JSONObject(str); // JSON object with above data
JSONObject demo = jsr.getJSONObject("Demo"); // get Demo which is a JSON object inside jsr.
JSONArray content = demo.getJSONArray("CONTENT");// get CONTENT which is Json array inside Demo
for (int i = 0; i < content.length(); i++) { // iterate over array to get inner JSON objects and extract values inside
JSONObject record = content.getJSONObject(i); // each item of Array is a JSON object
String ID = record.getString("ID");
String UID = record.getString("UID");
String DURATION = record.getString("DURATION");
}
}
catch (JSONException e) {
e.printStackTrace();
}
Note: Above code is specifc to org.Json API. Find appropriate methods in library you are using for Json handling
Use a loop that iterates through the Json Object and access each of the element
for(/**loop until the counter reaches the size of the json object**/) {
//Access each element based on the ID as below.
System.out.println(Demo.CONTENT[CurrentCounter].ID); //here CurrentCounter is index
System.out.println(Demo.CONTENT[CurrentCounter].UID); ..... //read through all ids
}
I guess you could use the 'get' Method on the JSONObject. If you don't know which key to look for, I suggest using a Method that returns all available keys, like the one called 'keys'. With these values, you could then traverse down in you structure. See here:
http://json-lib.sourceforge.net/apidocs/net/sf/json/JSONObject.html
I guess GSON will be a big help for you.
See here Parsing json object into a string
There is a samplecode as well
Create a class which have variables you want to read from json string.And Gson will handle the rest.
https://code.google.com/p/google-gson/
Example usage:
//convert the json string back to object
DataObject obj = gson.fromJson(br, DataObject.class);

How to get specific JSON data?

Hi I am trying to read JSON from an ReST API but Im getting a nullpointer exception because mycode is not correct.
I have a JSON that I am reading from looking like this :
processJSON({
"LocationList":{
"noNamespaceSchemaLocation":"http://api.vasttrafik.se/v1/hafasRestLocation.xsd",
"servertime":"16:13",
"serverdate":"2013-03-22",
"StopLocation":[{
"name":"Brunnsparken, Göteborg",
"lon":"11.967824",
"lat":"57.706944",
"id":"9021014001760000",
"idx":"1"
},{
"name":"Brunnsgatan, Göteborg",
"lon":"11.959455",
"lat":"57.693766",
"id":"9021014001745000",
"idx":"4"
},{
"name":"Brunnslyckan, Lerum",
"lon":"12.410219",
"lat":"57.812073",
"id":"9021014017260000",
"idx":"5"
},
Now I want the name from the JSON document depending on what the user inputs.
how do I do this with code?
My code that is wrong is like this :
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
public class JSONReader {
private String jsonData = "";
public String getJsonData(String location){
try {
URL url = new URL("http://api.vasttrafik.se/bin/rest.exe/v1/location.name?authKey=secret&format=json&jsonpCallback=processJSON&input=" + URLEncoder.encode(location, "UTF-8"));
URLConnection connection = url.openConnection();
BufferedReader readJsonFile = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String temp = "";
while((temp = readJsonFile.readLine()) != null){
jsonData += temp;
}
readJsonFile.close();
System.out.println(jsonData);
return jsonData;
}
catch (IOException e) {
}
return null;
}
public void JSONParsing(){
String location = Planner.getPlanner().getStartingLocation();
JSONObject obj =(JSONObject)JSONValue.parse(getJsonData(location));
//Set the text into the JList
if (obj.containsValue(location));
obj.get("name");
}
}
I want get the same name of the location out from the JSON as the user inputs.
How do I do this with code?
I think that you are asking how to parse your JSONObject and get the corresponding values out of it that the user is interested in. Below is an example of how you can pull apart the JSONObject to create a Map whose key is the String id (since the name does not seem to be unique) and whose value is the whole JSONObject. You can use this map to lookup the input from the user and find the appropriate LLA if that's what you are interested in.
public Map<String, JSONObject> createLocationMap(JSONObject jsonObj){
Map<String, JSONObject> nameToLocationMap = new HashMap<String, JSONObject>();
JSONObject locationList = (JSONObject) jsonObj.get("LocationList");
JSONArray array = (JSONArray) locationList.get("StopLocation");
for (int i = 0; i < array.length(); i++) {
String name = (String) ((JSONObject) array.get(i)).get("id");
nameToLocationMap.put(name, ((JSONObject)array.get(i)));
}
return nameToLocationMap;
}
You can tailor this method as you see fit. For example if you are interested in the relationship between the id and the name then you can create a similar method that uses those values instead of id and the entire JSONObject'. I hope that this helps~

Categories