Restructuring JSON file in JAVA - java

I am having the following sample from a JSON file:
[
{
"0":
{
"File":"file1.java",
"Class":"com.ETransitionActionType",
"Method":"values",
"Annotation":"Not Found"
}
},
{
"1":
{
"File":"file2.java",
"Class":"com.ETransitionParams",
"Method":"values",
"Annotation":"Not Found"
}
},
{
"2":
{
"File":"file3.java",
"Class":"com.phloc.commons.id.IHasID",
"Method":"getID",
"Annotation":"Not Found"
}
},
{
"4":
{
"File":"file3.java",
"Class":"com.ExecuteTransitionActionHandler",
"Method":"createBadRequestResponse",
"Annotation":"Not Found"
}
},
{
"5":
{
"File":"file3.java",
"Class":"com.ExecuteTransitionActionHandler",
"Method":"extractParametersFromAction",
"Annotation":"Not Found"
}
}]
How can I restructure this file using java so that it looks like:
[{
"file1.java": {
"com.ETransitionActionType": {
"values": {
"Annotation": "Not Found"
}
}
}
},
{
"file2.java": {
"com.ETransitionParams": {
"values": {
"Annotation": "Not Found"
}
}
}
},
{
"file3.java": {
"com.phloc.commons.id.IHasID": {
"getID": {
"Annotation": "Not Found"
}
},
"com.ExecuteTransitionActionHandler": {
"getID": {
"Annotation": "Not Found"
},
"extractParametersFromAction": {
"Annotation": "Not Found"
}
}
}
}
]
i.e. Going through the JSON file, searching it, and wherever the "File" attribute has the same value("file3.java" for example), we list all the relevant classes and methods inside and the same applies for the "Class" attribute, if it has the same name, we list all the methods inside it(So it's like comparing and sorting the values for the "File" and "Class" attributes).
I started with JSON simple library and wrote like the code below, but don't know how to go further!
Object object = (JSONArray)parser.parse(new FileReader("rawOutput.json"));
JSONArray jsonArray = (JSONArray) object;
for(int i = 0; i < jsonArray.size(); i++) {
System.out.println(jsonArray.get(i));
JSONObject jsonObject = (JSONObject)jsonArray.get(i);
String c = jsonObject.get("" + i + "").toString();
}
Any ideas? Your help is really appreciated!!!

I wrote a code to do what do you need but first you have to add this library to your project if you don't have already org.json.zip library, because I didn't have a library for parsing Json texts so I used this library for formatting the Json data, and I'm sorry if you don't understand the code completely because your request isn't so easy as yourself know and I created three functions to get the result and although I wrote some comments to understand easily, this is the code:-
Edit
...
import org.json.*;
...
...
public static void main(String[] args) throws JSONException {
System.out.println(getFormattedJson("json text"));
}
private static String getFormattedJson(String text) throws JSONException{
JSONArray result = new JSONArray();
JSONArray jsonArray = null;
//get the json array
jsonArray = new JSONArray(text);
//loop through items in the array and insert them formatted to the result
for (int i = 0; i < jsonArray.length(); i++) {
//get object inside the number
JSONObject object = getJsonChild(jsonArray.getJSONObject(i));
//get these attributes
String file = object.getString("File");
String clas = object.getString("Class");
String meth = object.getString("Method");
String anno = object.getString("Annotation");
//create a custom type of the object's attributes
Map<String, String> map = new HashMap<>();
map.put("Annotation", anno);
Map<String, Object> map1 = new HashMap<>();
map1.put(meth, map);
Map<String, Object> map2 = new HashMap<>();
map2.put(clas, map1);
Map<String, Object> map3 = new HashMap<>();
map3.put(file, map2);
//loop through repeating values to also add them to one value as you expected
for (int j = jsonArray.length() - 1; j > i; j--) {
JSONObject obj = getJsonChild(jsonArray.getJSONObject(j));
String file1 = obj.getString("File");
String clas1 = obj.getString("Class");
String meth1 = obj.getString("Method");
String anno1 = obj.getString("Annotation");
if (file1.equals(file)) {
if (map2.containsKey(clas1)) {
if (childrenContains(map2, meth1)) {
//if the difference was annotation value
map.put("Annotation", anno1);
} else {
//if the difference was method names
Map<String, String> map_ = new HashMap<>();
map_.put("Annotation", anno1);
((Map<String, Object>) map2.get(clas1)).put(meth1, map_);
}
} else {
//if the difference was class names
Map<String, String> map_ = new HashMap<>();
map_.put("Annotation", anno1);
Map<String, Object> map1_ = new HashMap<>();
map1_.put(meth1, map_);
map2.put(clas1, map1_);
}
//remove the (value added) object
jsonArray.remove(j);
}
}
//add the map to the result
result.put(map3);
}
return result.toString(4);
}
private static boolean childrenContains(Map<String, Object> map1, String meth1) {
for (String childKey : map1.keySet()) {
Map<String, Object> child = (Map<String, Object>) map1.get(childKey);
if (child.containsKey(meth1))
return true;
}
return false;
}
private static JSONObject getJsonChild(JSONObject object) throws JSONException {
Iterator<String> keys = object.keys();
String key = "";
while (keys.hasNext()) {
key = (String) keys.next();
}
return object.getJSONObject(key);
}
And the result for your sample using my code is:-
[
{"file1.java": {"com.ETransitionActionType": {"values": {"Annotation": "Not Found"}}}},
{"file2.java": {"com.ETransitionParams": {"values": {"Annotation": "Not Found"}}}},
{"file3.java": {
"com.ExecuteTransitionActionHandler": {
"createBadRequestResponse": {"Annotation": "Not Found"},
"extractParametersFromAction": {"Annotation": "Not Found"}
},
"com.phloc.commons.id.IHasID": {"getID": {"Annotation": "Not Found"}}
}}
]
And if you want to get the json data from a file so use the following function to create the JSONArray easily:-
private static JSONArray readFromFile(String filePath){
try {
BufferedReader br = new BufferedReader(new FileReader(filePath));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append(System.lineSeparator());
line = br.readLine();
}
return new JSONArray(sb.toString());
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
And use it instead the text json data:-
...
//get the json array
jsonArray = readFromFile("FilePath");
...

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
public class Foo {
public static void main(String... args) throws IOException {
String json = formatJson(new FileReader("rawOutput.json"));
System.out.println(json);
}
public static String formatJson(Reader reader) throws IOException {
// group array items by fileName
final Function<List<Map<String, Object>>, Map<String, List<Object>>> groupByFileName =
data -> data.stream().collect(Collectors.groupingBy(map -> (String)map.get("File"), TreeMap::new,
Collectors.mapping(Function.identity(), Collectors.toList())));
// convert source item structure into required
final Function<Map.Entry<String, List<Object>>, Map<String, Object>> convert = entry -> {
Map<String, Map<String, Map<String, String>>> tmp = new LinkedHashMap<>();
entry.getValue().stream()
.map(value -> (Map<String, String>)value)
.forEach(map -> {
Map<String, Map<String, String>> classes = tmp.computeIfAbsent(map.get("Class"), cls -> new TreeMap<>());
Map<String, String> methods = classes.computeIfAbsent(map.get("Method"), method -> new TreeMap<>());
map.entrySet().stream()
.filter(e -> !"Class".equals(e.getKey()) && !"Method".equals(e.getKey()) && !"File".equals(e.getKey()))
.forEach(e -> methods.put(e.getKey(), e.getValue()));
});
return Collections.singletonMap(entry.getKey(), tmp);
};
ObjectMapper mapper = new ObjectMapper();
// read json as array of Maps
List<Map<String, Object>> data = Arrays.stream(mapper.readValue(reader, Map[].class))
.map(map -> map.values().iterator().next())
.map(item -> (Map<String, Object>)item)
.collect(Collectors.toList());
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(groupByFileName.apply(data).entrySet().stream()
.map(convert).collect(Collectors.toList()));
}
}

You could create a map of maps to represent your grouping by "File" and "Class" for your list of (inner) JSON objects. It might look similar to
final Function<JSONObject, String> fileFunction = (JSONObject jsonObject) -> jsonObject.getString("File");
final Function<JSONObject, String> classFunction = (JSONObject jsonObject) -> jsonObject.getString("Class");
final Map<String, Map<String, List<JSONObject>>> groupedJsonObjects = jsonObjects.stream()
.collect(Collectors.groupingBy(fileFunction, Collectors.groupingBy(classFunction)));

Related

How to create array in json object

I am using something like this-
String Number1=to_1;
String Number2=to_2;
String[] arrayNumbers = new String[] {(char)34+Number1+(char)34,(char)34+Number2+(char)34};
System.out.println(Arrays.toString(arrayNumbers));
JSONObject jsonObj = new JSONObject();
jsonObj.put("to",Arrays.toString(arrayNumbers));
jsonObj.put("type",type);
jsonObj.put("callback",callbackUrl);
JSONArray array = new JSONArray();
JSONObject Array_item = new JSONObject();
jsonObj.put(type, array);
Array_item.put("caption",captionName);
array.add(Array_item);
System.out.println(jsonObj.toString());
Expected-
{
"to":["91890xx", "91890xx"],
"type": "document", "document" : {"caption" : "doc"},
"callback":"{{callback}}"
}
Actual- {"document":[{"caption":"hello"}],"callback":"{{callback}}","to":"[\"91890xxx\", \"91890xx\"]","type":"document"}
I don't know any more logic to remove the out double quotes of to number where as its considering that to a string where as both the numbers should be array format as mentioned in Expected.
First, I show you the correct codes:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class Test {
/**
* <pre>
* {
* "to":["91890xx", "91890xx"],
* "type": "document",
* "document" : {"caption" : "doc"},
* "callback":"{{callback}}"
* }
* </pre>
*
* #param args
* #throws JSONException
*/
public static void main(String[] args) throws JSONException {
String number1 = "91890";
String number2 = "91890";
String[] numbers = new String[]{number1, number2};
JSONArray toNode = new JSONArray();
for (String number : numbers) {
toNode.put(number);
}
JSONObject jsonObj = new JSONObject();
jsonObj.put("to", toNode);
jsonObj.put("type", "document");
jsonObj.put("document", new JSONObject().put("caption", "doc"));
jsonObj.put("callback", "{{callback}}");
System.out.println(jsonObj.toString());
}
}
Result:
{"document":{"caption":"doc"},"callback":"{{callback}}","to":["91890","91890"],"type":"document"}
If you want create a josn array node, you show use JSONArray, and use JSONArray#put(*) method to add elements.
Put string into JSONArray or JSONObject, you don't need wrap the string with quote("). Besides, you should write \" instead of (char) 34 which is a little obscure in Java.
The following case is used to reply comments.
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.math.BigDecimal;
import java.net.URI;
import java.net.URL;
import java.util.*;
public class Test1 {
public static void main(String[] args) throws JSONException {
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", new Date());
map.put("key3", 1);
map.put("key4", null);
map.put("key5", Collections.singletonMap("key5-key1", "value"));
map.put("key6", Arrays.asList(1, 2, 3, 4));
map.put("key7", BigDecimal.TEN);
map.put("key8", new String[]{"a", "b", "c"});
map.put("key9", TestEnum.A);
map.put("key10", new TestEnum[]{TestEnum.A, TestEnum.B, TestEnum.C});
Object json = buildJsonObj(map);
System.out.println(json);
}
private static Object buildJsonObj(Object source) throws JSONException {
if (source == null) {
return null;
}
if (isSimpleValueType(source.getClass())) {
return source;
}
if (source instanceof Map) {
Map<Object, Object> map = (Map<Object, Object>) source;
JSONObject jsonObject = new JSONObject();
for (Map.Entry<Object, Object> entry : map.entrySet()) {
Object key = entry.getKey();
if (!(key instanceof String)) {
throw new IllegalArgumentException("key must be string.");
}
jsonObject.put((String) key, buildJsonObj(entry.getValue()));
}
return jsonObject;
}
if (source instanceof Iterable) {
Iterable<Object> iterable = (Iterable<Object>) source;
JSONArray jsonArray = new JSONArray();
for (Object value : iterable) {
jsonArray.put(buildJsonObj(value));
}
return jsonArray;
}
if (source.getClass().isArray()) {
Object[] array = (Object[]) source;
JSONArray jsonArray = new JSONArray();
for (Object value : array) {
jsonArray.put(buildJsonObj(value));
}
return jsonArray;
}
throw new IllegalArgumentException("Unsupported type: " + source + ".");
}
private static boolean isSimpleValueType(Class<?> clazz) {
return (Enum.class.isAssignableFrom(clazz) ||
CharSequence.class.isAssignableFrom(clazz) ||
Number.class.isAssignableFrom(clazz) ||
Date.class.isAssignableFrom(clazz) ||
URI.class == clazz || URL.class == clazz ||
Locale.class == clazz);
}
public enum TestEnum {
A, B, C
}
}
Result:
{"key1":"value1","key2":"Thu Mar 14 20:20:49 CST 2019","key5":{"key5-key1":"value"},"key6":[1,2,3,4],"key3":1,"key9":"A","key7":10,"key8":["a","b","c"],"key10":["A","B","C"]}
Replace line
jsonObj.put("to",Arrays.toString(arrayNumbers));
to
jsonObj.put("to", Arrays.asList(arrayNumbers));
Your value is String of 'to',so can you please convert string to json after that you can convert json to array.
Replace
jsonObj.put("to",Arrays.toString(arrayNumbers));
With
jsonObj.put("to",arrayNumbers);
let a = {"document":[{"caption":"hello"}],"callback":"{{callback}}","to":"[\"91890xxx\", \"91890xx\"]","type":"document"};
a = JSON.parse(JSON.stringify(a));
let b = JSON.parse(a.to);
a.to = b;
console.log(a);
This is the exact structure of you required json.
{
"to": ["91890xx", "91890xx"],
"type": "document",
"document": {
"caption": "doc"
},
"callback": "{{callback}}"
}
To Remove the double quotes, please use replace function as shown below
String Number1="[\"91890xxx\", \"91890xx\"]";
Number1.replace("\\/", "");
System.out.println("Excepted output:"+Number1);
output:
Excepted output:["91890xxx", "91890xx"]

Parsing JSON into a object

I'm trying to parse this JSON using gson:
{"hvs1":{"16191":[["TestFile3","C",["A"]],["TestFile3","-",["1G","1A"]]],"16193":[["TestFile3","C",["G"]]]},"hvs2":{"25":[["TestFile3","-",["1A"]]]},"outros":{"16423":[["TestFile3","A",["T"]]]}}
Into this object
public class Results {
private String regiaoAfetada;
private String posicaoReferencia;
private String nomeDoArquivo;
private String baseAlteradaReferencia;
private List<String> mutacaoEncontrada;
//get and set
}
And my test class to try to achive this, but I'm getting a error.
public class JsonTeste {
public static void main(String[] args) {
Gson gson = new Gson();
try (Reader reader = new FileReader("foobar.json")) {
Type type = new TypeToken<TreeMap<String, TreeMap>>() {
}.getType();
TreeMap<String, TreeMap<String, List<List<List<String>>>>> map = gson.fromJson(reader, type);
List<Results> listaMutacoes = new ArrayList<Results>();
for (Entry<String, TreeMap<String, List<List<List<String>>>>> regioesMap : map.entrySet()) {
TreeMap<String, List<List<List<String>>>> regiaoUm = regioesMap.getValue();
for (Entry<String, List<List<List<String>>>> regiaoUmResult : regiaoUm.entrySet()) {
List<List<List<String>>> resultados = regiaoUmResult.getValue();
for (List<List<String>> list : resultados) {
Results resultado = new Results();
resultado.setRegiaoAfetada(regioesMap.getKey());
resultado.setPosicaoReferencia(regiaoUmResult.getKey());
resultado.setNomeDoArquivo(list.get(0).toString());
resultado.setBaseAlteradaReferencia(list.get(1).toString());
resultado.setMutacaoEncontrada(list.get(2));
listaMutacoes.add(resultado);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
The problem is when I try to parse this part
[
"TestFile3",
"-",
[
"1G",
"1A"
]
]
Because I have two Strings and a Array inside, so the problem Is when I try to place "TestFile3" into setNomeDoArquivo, but even if I comment this line, i get the same error in the second line.
resultado.setNomeDoArquivo(list.get(0).toString());
resultado.setBaseAlteradaReferencia(list.get(1).toString());
java.lang.ClassCastException: java.lang.String cannot be cast to java.util.List
Can you guys help me?
The List resultados is of List<string> or List<List<String>>.When you get the item of resultados it can be one of them. So to generalized declare it as List<List<Object>>
Try The below Code :
Gson gson = new Gson();
try (Reader reader = new FileReader("foobar.json")) {
Type type = new TypeToken<TreeMap<String, TreeMap>>() {
}.getType();
TreeMap<String, TreeMap<String, List<List<Object>>>> map = gson.fromJson(reader, type);
List<Results> listaMutacoes = new ArrayList<>();
for (Map.Entry<String, TreeMap<String, List<List<Object>>>> regioesMap : map.entrySet()) {
TreeMap<String, List<List<Object>>> regiaoUm = regioesMap.getValue();
for (Map.Entry<String, List<List<Object>>> regiaoUmResult : regiaoUm.entrySet()) {
List<List<Object>> resultados = regiaoUmResult.getValue();
for (List<Object> list : resultados) {
System.out.println(list);
Results resultado = new Results();
resultado.setRegiaoAfetada(regioesMap.getKey());
resultado.setPosicaoReferencia(regiaoUmResult.getKey());
resultado.setNomeDoArquivo((String) list.get(0));
resultado.setBaseAlteradaReferencia((String) list.get(1));
resultado.setMutacaoEncontrada((List<String>) list.get(2));
listaMutacoes.add(resultado);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}

Jackson ObjectMapper configuration - error JsonParseException: Unexpected character ('b' (code 98)):

I have generated JSON in the following format
[{"empNo":"2390","empName":"JAMES","projects":{"projectId":209,"projectName":"Z560"}}]
How do I configure ObjectMapper for the above?
I have declared ObjectMapper as
private static final ObjectMapper om = new ObjectMapper();
static {
om.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
om.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
om.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS,
true);
om.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES,
false);
om.getSerializationConfig().setSerializationInclusion
(JsonSerialize.Inclusion.NON_NULL);
}
However I am still getting the following error
com.sun.jersey.spi.container.ContainerResponse mapMappableContainerException
SEVERE: The exception contained within MappableContainerException could not
be mapped to a response, re-throwing to the HTTP container
org.codehaus.jackson.JsonParseException: Unexpected character ('b' (code 98)):
expected a valid value (number, String, array, object,
'true', 'false' or 'null') at [Source: java.io.StringReader#1fef0b44; line: 1,
column: 2]
Expected output is
{"empNo":"2390","empName":"JAMES","projectId":"209","projectName":"Z560"}
A bit lengthy, can be optimized. refer this for more.
public static void main(String[] args) throws IOException {
String originalJson = "{\"empNo\":\"2390\",\"empName\":\"JAMES\",\"projects\":{\"projectId\":209,\"projectName\":\"Z560\"}}";
try {
JSONObject jsonObject = new JSONObject(originalJson);
Map<String, Object> map = getMap(jsonObject);
System.out.println("My Old Map => " + map);
Map<String, Object> newMap = new HashMap<String, Object>();
for (Map.Entry<String, Object> entry : map.entrySet()) {
if (entry.getKey().equals("projects")) {
Map<String, Object> projectMap = (Map<String, Object>) entry.getValue();
for (Map.Entry<String, Object> entry1 : projectMap.entrySet()) {
newMap.put(entry1.getKey(), entry1.getValue());
}
} else {
newMap.put(entry.getKey(), entry.getValue().toString());
}
}
JSONObject jsonObject1 = new JSONObject(newMap);
System.out.println("My New Map => " + newMap);
System.out.println("Expected Json String => " + jsonObject1.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static Map getMap(JSONObject object) {
Map<String, Object> map = new HashMap<String, Object>();
Object jsonObject = null;
String key = null;
Object value = null;
try {
Iterator<String> keys = object.keys();
while (keys.hasNext()) {
key = null;
value = null;
key = keys.next();
if (null != key && !object.isNull(key)) {
value = object.get(key);
}
if (value instanceof JSONObject) {
map.put(key, getMap((JSONObject) value));
continue;
}
if (value instanceof JSONArray) {
JSONArray array = ((JSONArray) value);
List list = new ArrayList();
for (int i = 0 ; i < array.length() ; i++) {
jsonObject = array.get(i);
if (jsonObject instanceof JSONObject) {
list.add(getMap((JSONObject) jsonObject));
} else {
list.add(jsonObject);
}
}
map.put(key, list);
continue;
}
map.put(key, value);
}
} catch (Exception e) {
System.out.println(e);
}
return map;
}
Output
My Old Map => {projects={projectId=209, projectName=Z560},
empName=JAMES, empNo=2390}
My New Map => {empName=JAMES, empNo=2390, projectId=209,
projectName=Z560}
Expected Json String =>
{"empName":"JAMES","empNo":"2390","projectId":209,"projectName":"Z560"}

how to convert json string to map dynamically

I have a json ouput like this -
{"menu": {
"id": "12",
"value": "File",
"popup": {
"menuitem": [
{"op1": "New", "op11": "CreateNewDoc()"},
{"op2": "Open", "op21": "OpenDoc()"},
{"op3": "Close", "op31": "CloseDoc()"}
]
}
}}
I want whatever is the key and order, it should return the key-value pair in a map like this and I do not want to harcode any key-
id=12
value=File
op1=New
op11=CreateNewDoc()
op2=Open
op21=OpenDoc()
op3=Close
op31=CloseDoc()
how will I do it?
Using the standard Java JSON Stream APIs, this will produce the java.util.Map you want:
Map<String, String> values = new HashMap<>();
String keyName = null;
JsonParser jsonParser = Json.createParser(new StringReader(json));
while (jsonParser.hasNext())
{
JsonParser.Event event = jsonParser.next();
if (JsonParser.Event.KEY_NAME.equals(event))
{
keyName = jsonParser.getString();
}
else if (JsonParser.Event.VALUE_STRING.equals(event))
{
values.put(keyName, jsonParser.getString());
}
}
I have used Jackson Json.
first. I changed Json string to JsonNode.
ex) JsonString to JsonNode
public static JsonNode jsonStringToJsonNode(String json){
ObjectMapper mp = new ObjectMapper();
try {
return mp.readValue(json, JsonNode.class);
} catch (JsonParseException e) {
} catch (JsonMappingException e) {
} catch (IOException e) {
}
return null;
}
Usage.
ex)
JsonNode json = jsonStringToJsonNode(jsonstring)
json.get("menu").get("id") => result 12
I hope it will help you.
Simply convert JSON string into Map<String,Object> then extract the desired values using Recursion.
Recursion method:
public static void process(String key, Object value, Map<String, String> newMap){
if (value instanceof String) {
newMap.put(key, (String) value);
} else if (value instanceof Map) {
Map<String, Object> map = (Map<String, Object>) value;
for (Entry<String, Object> entry : map.entrySet()) {
process(entry.getKey(), entry.getValue(), newMap);
}
} else if (value instanceof List) {
List<Object> list = (List<Object>) value;
for (Object obj : list) {
process(key, obj, newMap);
}
}
}
You can try any one.
sample code: (using Jackson Library)
TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {};
ObjectMapper mapper = new ObjectMapper();
try {
Map<String, Object> data = mapper.readValue(jsonString, typeRef);
Map<String, String> newMap = new HashMap<String, String>();
process("menu", data.get("menu"), newMap);
System.out.println(new JSONObject(newMap));
} catch (Exception e) {
System.out.println("There might be some issue with the JSON string");
}
sample code: using GSON Library
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> data = new Gson().fromJson(jsonString, type);
Map<String, String> newMap = new HashMap<String, String>();
process("menu", data.get("menu"), newMap);
System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(newMap));
output:
{
"op1": "New",
"id": "12",
"op21": "OpenDoc()",
"op2": "Open",
"op3": "Close",
"op11": "CreateNewDoc()",
"value": "File",
"op31": "CloseDoc()"
}

Parsing JSON in Java without knowing JSON format

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?
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());
}
}
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...
}
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;
}
}
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();
}
}
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;
}
}
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)

Categories

Resources