how to convert json string to map dynamically - java

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()"
}

Related

Restructuring JSON file in 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)));

How to map JSON (custom)

I'm a beginner and I need to sort from a JSON to be analyzed later.
I need to know the JSON fields and if it has arrays or subcategories.
I have to map JSON input, for example:
{
"car":"Audi",
"model":"2010",
"price":"30000",
"colors":[
"Grey",
"White",
"Black"
],
"otro":{
"a":1,
"b":2,
"c":[
{
"c11":"c11",
"c12":"c12"
},
{
"c21":"c21",
"c22":"c22"
}
]
}
}
Waiting as output mapping:
car
model
price
colors[]
otro.a
otro.b
otro.c[].c11
otro.c[].c12
otro.c[].c21
otro.c[].c22
This is my code:
public static void main(String[] args) {
try {
ObjectMapper mapper = new ObjectMapper();
String json = "{\"car\":\"Audi\",\"model\":\"2010\",\"price\":\"30000\",\"colors\":[\"Grey\",\"White\",\"Black\"],\"otro\":{\"a\":1,\"b\":2,\"c\":[{\"c11\":\"c11\", \"c12\":\"c12\"},{\"c21\":\"c21\", \"c22\":\"c22\"}]}}";
Map<String, Object> map = new HashMap<String, Object>();
// convert JSON string to Map
map = mapper.readValue(json, new TypeReference<Map<String, Object>>() {
});
for (Map.Entry<String, Object> entry : map.entrySet()) {
System.out.println(entry.getKey() + " - " + entry.getValue().getClass());
if (entry.getValue() instanceof List) {
for (Object object : ((List)entry.getValue())) {
System.out.println("\t-- " + object.getClass());
}
}
}
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
You can make a POJO and map the JSON to the POJO and do whatever you would like with it. Another option that is pretty powerful is using the JsonNode objects. They have lots of helper methods for figuring out the types of each node. Here are some quick examples https://www.stubbornjava.com/posts/practical-jackson-objectmapper-configuration#jsonnodes-and-nested-objects

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"}

Serialize JSON document using Jackson

I am trying to serialize JSON document using Jackson library. Below is my JSON document that I have created by hand. Now I need to serialize this document using Jackson
Example-A
{
"v" : {
"site_id" : 0,
"price_score" : 0.5,
"confidence_score" : 0.2,
"categories": {
"123" : {
"price_score": "0.5",
"confidence_score": "0.2"
},
"321" : {
"price_score": "0.2",
"confidence_score": "0.4"
}
}
}
}
I am able to make this part of JSON document till now with my below code and using Jackson-
Example-B
{
"v" : {
"site_id" : 0,
"price_score" : 0.5,
"confidence_score" : 0.2
}
}
Now, I am not able to understand how do I add the list of categories (as shown in Example-A) portion in my Example-B JSON document with my below code?
public static void main(String[] args) {
Map<String, Object> props = new HashMap<String, Object>();
props.put("site-id", 0);
props.put("price-score", 0.5);
props.put("confidence-score", 0.2);
AttributeValue av = new AttributeValue();
av.setProperties(props);
/**
* this will print out the JSON document like I shown in my Example-B
* but I need to make it look like as in Example-A. I am not sure how
* to achieve that?
*/
System.out.println(av);
// serialize it
try {
String jsonStr = JsonMapperFactory.get().writeValueAsString(attr);
System.out.println(jsonStr);
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Can anybody help me with that?
Solution 1
In you case you can do it with
Map<String, Object> props = new HashMap<String, Object>();
props.put("site-id", 0);
props.put("price-score", 0.5);
props.put("confidence-score", 0.2);
Map<String, String> category123 = new HashMap<String, String>();
category123.put("price_score", "0.5");
category123.put("confidence_score", "0.2");
Map<String, String> category321 = new HashMap<String, String>();
category123.put("price_score", "0.2");
category123.put("confidence_score", "0.4");
Map<String, Object> categories = new HashMap<String, Object>();
categories.put("123", category123);
categories.put("321", category321);
props.put("categories", categories);
Solution 2:
Or you can simplify it with additional classes, e.g.:
public class Category
{
private String price_score;
private String confidence_score;
public Category(String price_score, String confidence_score)
{
this.price_score = price_score;
this.confidence_score = confidence_score;
}
public Category()
{
}
// getters/setters
}
main method
Map<String, Object> props = new HashMap<String, Object>();
props.put("site-id", 0);
props.put("price-score", 0.5);
props.put("confidence-score", 0.2);
Map<String, Category> categories = new HashMap<String, Category>();
categories.put("123", new Category("0.4", "0.2"));
categories.put("321", new Category("0.2", "0.5"));
props.put("categories", categories);

Categories

Resources