Parsing JSON in Java without knowing JSON format

JavaJsonParsingJackson

Java Problem Overview


I am trying to parse JSON strings in Java and find the key-value pairs so that I can determine the approximate structure of the JSON object since object structure of JSON string is unknown.

For example, one execution may have a JSON string like this:

  {"id" : 12345, "days" : [ "Monday", "Wednesday" ], "person" : { "firstName" : "David", "lastName" : "Menoyo" } }

And another like this:

  {"url" : "http://someurl.com", "method" : "POST", "isauth" : false }

How would I cycle through the various JSON elements and determine the keys and their values? I looked at jackson-core's JsonParser. I see how I can grab the next "token" and determine what type of token it is (i.e., field name, value, array start, etc), but, I don't know how to grab the actual token's value.

For example:

public void parse(String json)  {
  try {
     JsonFactory f = new JsonFactory();
     JsonParser parser = f.createParser(json);
     JsonToken token = parser.nextToken();
     while (token != null) {
        if (token.equals(JsonToken.START_ARRAY)) {
           logger.debug("Start Array : " + token.toString());
        } else if (token.equals(JsonToken.END_ARRAY)) {
           logger.debug("End Array : " + token.toString());
        } else if (token.equals(JsonToken.START_OBJECT)) {
           logger.debug("Start Object : " + token.toString());
        } else if (token.equals(JsonToken.END_OBJECT)) {
           logger.debug("End Object : " + token.toString());
        } else if (token.equals(JsonToken.FIELD_NAME)) {
           logger.debug("Field Name : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_FALSE)) {
           logger.debug("Value False : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_NULL)) {
           logger.debug("Value Null : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_NUMBER_FLOAT)) {
           logger.debug("Value Number Float : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_NUMBER_INT)) {
          logger.debug("Value Number Int : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_STRING)) {
           logger.debug("Value String : " + token.toString());
        } else if (token.equals(JsonToken.VALUE_TRUE)) {
           logger.debug("Value True : " + token.toString());
        } else {
           logger.debug("Something else : " + token.toString());
        }
        token = parser.nextToken();
     }
  } catch (Exception e) {
     logger.error("", e);
  }
}

Is there a class in jackson or some other library (gson or simple-json) that produces a tree, or allows one to cycle through the json elements and obtain the actual key names in addition to the values?

Java Solutions


Solution 1 - Java

Take a look at Jacksons built-in tree model feature.

And your code will be:

public void parse(String json)  {
       JsonFactory factory = new JsonFactory();
 
       ObjectMapper mapper = new ObjectMapper(factory);
       JsonNode rootNode = mapper.readTree(json);  

       Iterator<Map.Entry<String,JsonNode>> fieldsIterator = rootNode.fields();
       while (fieldsIterator.hasNext()) {

           Map.Entry<String,JsonNode> field = fieldsIterator.next();
           System.out.println("Key: " + field.getKey() + "\tValue:" + field.getValue());
       }
}

Solution 2 - Java

If a different library is fine for you, you could try org.json:

JSONObject object = new JSONObject(myJSONString);
String[] keys = JSONObject.getNames(object);

for (String key : keys)
{
    Object value = object.get(key);
    // Determine type of value and do something with it...
}

Solution 3 - Java

Find the following code for Unknown Json Object parsing using Gson library.

public class JsonParsing {
static JsonParser parser = new JsonParser();

public static HashMap<String, Object> createHashMapFromJsonString(String json) {

    JsonObject object = (JsonObject) parser.parse(json);
    Set<Map.Entry<String, JsonElement>> set = object.entrySet();
    Iterator<Map.Entry<String, JsonElement>> iterator = set.iterator();
    HashMap<String, Object> map = new HashMap<String, Object>();

    while (iterator.hasNext()) {

        Map.Entry<String, JsonElement> entry = iterator.next();
        String key = entry.getKey();
        JsonElement value = entry.getValue();

        if (null != value) {
            if (!value.isJsonPrimitive()) {
                if (value.isJsonObject()) {

                    map.put(key, createHashMapFromJsonString(value.toString()));
                } else if (value.isJsonArray() && value.toString().contains(":")) {

                    List<HashMap<String, Object>> list = new ArrayList<>();
                    JsonArray array = value.getAsJsonArray();
                    if (null != array) {
                        for (JsonElement element : array) {
                            list.add(createHashMapFromJsonString(element.toString()));
                        }
                        map.put(key, list);
                    }
                } else if (value.isJsonArray() && !value.toString().contains(":")) {
                    map.put(key, value.getAsJsonArray());
                }
            } else {
                map.put(key, value.getAsString());
            }
        }
    }
    return map;
}
}

Solution 4 - Java

JSON of unknown format to HashMap

writing JSON And reading Json

public static JsonParser parser = new JsonParser();
public static void main(String args[]) {
     writeJson("JsonFile.json");
     readgson("JsonFile.json");
}
public static void readgson(String file) {
    try {
        System.out.println( "Reading JSON file from Java program" );
        
        FileReader fileReader = new FileReader( file );
        com.google.gson.JsonObject object = (JsonObject) parser.parse( fileReader );
        
        Set <java.util.Map.Entry<String, com.google.gson.JsonElement>> keys = object.entrySet();
        if ( keys.isEmpty() ) {
			System.out.println( "Empty JSON Object" );
		}else {
			Map<String, Object> map = json_UnKnown_Format( keys );
			System.out.println("Json 2 Map : "+map);
		}
        
    } catch (IOException ex) {
    	System.out.println("Input File Does not Exists.");
    }
}
public static Map<String, Object> json_UnKnown_Format( Set <java.util.Map.Entry<String, com.google.gson.JsonElement>> keys ){
	Map<String, Object> jsonMap = new HashMap<String, Object>();
    for (Entry<String, JsonElement> entry : keys) {
		String keyEntry = entry.getKey();
		System.out.println(keyEntry + " : ");
		JsonElement valuesEntry =  entry.getValue();
		if (valuesEntry.isJsonNull()) {
			System.out.println(valuesEntry);
			jsonMap.put(keyEntry, valuesEntry);
		}else if (valuesEntry.isJsonPrimitive()) {
			System.out.println("P - "+valuesEntry);
			jsonMap.put(keyEntry, valuesEntry);
		}else if (valuesEntry.isJsonArray()) {
			JsonArray array = valuesEntry.getAsJsonArray();
			List<Object> array2List = new ArrayList<Object>();
			for (JsonElement jsonElements : array) {
				System.out.println("A - "+jsonElements);
				array2List.add(jsonElements);
			}
			jsonMap.put(keyEntry, array2List);
		}else if (valuesEntry.isJsonObject()) {				
			 com.google.gson.JsonObject obj = (JsonObject) parser.parse(valuesEntry.toString());		            
	         Set <java.util.Map.Entry<String, com.google.gson.JsonElement>> obj_key = obj.entrySet();
	         jsonMap.put(keyEntry, json_UnKnown_Format(obj_key));
		}
    }
	return jsonMap;
}
@SuppressWarnings("unchecked")
public static void writeJson( String file ) {

    JSONObject json = new JSONObject();
    
    json.put("Key1", "Value");
    json.put("Key2", 777); // Converts to "777"
    json.put("Key3", null);
    json.put("Key4", false);

        JSONArray jsonArray = new JSONArray();
        jsonArray.put("Array-Value1");
        jsonArray.put(10); 
        jsonArray.put("Array-Value2");

    json.put("Array : ", jsonArray); // "Array":["Array-Value1", 10,"Array-Value2"]
    
        JSONObject jsonObj = new JSONObject();
        jsonObj.put("Obj-Key1", 20);
        jsonObj.put("Obj-Key2", "Value2");
        jsonObj.put(4, "Value2"); // Converts to "4"
    
    json.put("InnerObject", jsonObj);
    
        JSONObject jsonObjArray = new JSONObject();
	        JSONArray objArray = new JSONArray();
	        objArray.put("Obj-Array1");
	        objArray.put(0, "Obj-Array3");
        jsonObjArray.put("ObjectArray", objArray);
    
    json.put("InnerObjectArray", jsonObjArray);
    
        Map<String, Integer> sortedTree = new TreeMap<String, Integer>();
        sortedTree.put("Sorted1", 10);
        sortedTree.put("Sorted2", 103);
        sortedTree.put("Sorted3", 14);
    
    json.put("TreeMap", sortedTree);        

    try {
        System.out.println("Writting JSON into file ...");
        System.out.println(json);
        FileWriter jsonFileWriter = new FileWriter(file);
        jsonFileWriter.write(json.toJSONString());
        jsonFileWriter.flush();
        jsonFileWriter.close();
        System.out.println("Done");

    } catch (IOException e) { 
        e.printStackTrace();
    }
    
}

Solution 5 - Java

Here is a sample I wrote shows how I parse a json and mess every number inside it:

public class JsonParser {

	public static Object parseAndMess(Object object) throws IOException {
		String json = JsonUtil.toJson(object);
		JsonNode jsonNode = parseAndMess(json);
		if(null != jsonNode)
			return JsonUtil.toObject(jsonNode, object.getClass());

		return null;
	}

	public static JsonNode parseAndMess(String json) throws IOException {
		JsonNode rootNode = parse(json);
		return mess(rootNode, new Random());
	}

	private static JsonNode parse(String json) throws IOException {
		JsonFactory factory = new JsonFactory();
		ObjectMapper mapper = new ObjectMapper(factory);
		JsonNode rootNode = mapper.readTree(json);
		return rootNode;

	}

	private static JsonNode mess(JsonNode rootNode, Random rand) throws IOException {
		if (rootNode instanceof ObjectNode) {
			Iterator<Map.Entry<String, JsonNode>> fieldsIterator = rootNode.fields();
			while (fieldsIterator.hasNext()) {
				Map.Entry<String, JsonNode> field = fieldsIterator.next();
				replaceObjectNode((ObjectNode) rootNode, field, rand);
			}
		} else if (rootNode instanceof ArrayNode) {
			ArrayNode arrayNode = ((ArrayNode) rootNode);
			replaceArrayNode(arrayNode, rand);
		}
		return rootNode;
	}

	private static void replaceObjectNode(ObjectNode rootNode, Map.Entry<String, JsonNode> field, Random rand)
			throws IOException {
		JsonNode childNode = field.getValue();
		if (childNode instanceof IntNode) {
			(rootNode).put(field.getKey(), rand.nextInt(1000));
		} else if (childNode instanceof LongNode) {
			(rootNode).put(field.getKey(), rand.nextInt(1000000));
		} else if (childNode instanceof FloatNode) {
			(rootNode).put(field.getKey(), format(rand.nextFloat()));
		} else if (childNode instanceof DoubleNode) {
			(rootNode).put(field.getKey(), format(rand.nextFloat()));
		} else {
			mess(childNode, rand);
		}
	}

	private static void replaceArrayNode(ArrayNode arrayNode, Random rand) throws IOException {
		int arrayLength = arrayNode.size();
		if(arrayLength == 0)
			return;
		if (arrayNode.get(0) instanceof IntNode) {
			for (int i = 0; i < arrayLength; i++) {
				arrayNode.set(i, new IntNode(rand.nextInt(10000)));
			}
		} else if (arrayNode.get(0) instanceof LongNode) {
			arrayNode.removeAll();
			for (int i = 0; i < arrayLength; i++) {
				arrayNode.add(rand.nextInt(1000000));
			}
		} else if (arrayNode.get(0) instanceof FloatNode) {
			arrayNode.removeAll();
			for (int i = 0; i < arrayLength; i++) {
				arrayNode.add(format(rand.nextFloat()));
			}
		} else if (arrayNode.get(0) instanceof DoubleNode) {
			arrayNode.removeAll();
			for (int i = 0; i < arrayLength; i++) {
				arrayNode.add(format(rand.nextFloat()));
			}
		} else {
			for (int i = 0; i < arrayLength; i++) {
				mess(arrayNode.get(i), rand);
			}
		}
	}

	public static void print(JsonNode rootNode) throws IOException {
		System.out.println(rootNode.toString());
	}

	private static double format(float a) {
		return Math.round(a * 10000.0) / 100.0;
	}
}

Solution 6 - Java

Would you be satisfied with a Map from Jackson?

ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = objectMapper.readValue(jsonString, new TypeReference<HashMap<String,Object>>(){});

Or maybe a JsonNode?

JsonNode jsonNode = objectMapper.readTree(String jsonString) 

Solution 7 - Java

To get JSON quickly into Java objects (Maps) that you can then 'drill' and work with, you can use json-io (https://github.com/jdereg/json-io). This library will let you read in a JSON String, and get back a 'Map of Maps' representation.

If you have the corresponding Java classes in your JVM, you can read the JSON in and it will parse it directly into instances of the Java classes.

JsonReader.jsonToMaps(String json)

where json is the String containing the JSON to be read. The return value is a Map where the keys will contain the JSON fields, and the values will contain the associated values.

JsonReader.jsonToJava(String json) 

will read the same JSON string in, and the return value will be the Java instance that was serialized into the JSON. Use this API if you have the classes in your JVM that were written by

JsonWriter.objectToJson(MyClass foo).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionwhyceewhiteView Question on Stackoverflow
Solution 1 - Javauser987339View Answer on Stackoverflow
Solution 2 - JavaIgnitorView Answer on Stackoverflow
Solution 3 - Javachandrasekhar majjiView Answer on Stackoverflow
Solution 4 - JavaYashView Answer on Stackoverflow
Solution 5 - JavaPeiming HuView Answer on Stackoverflow
Solution 6 - JavaVidyaView Answer on Stackoverflow
Solution 7 - JavaJohn DeRegnaucourtView Answer on Stackoverflow