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
Related
I have a string like this
{"key0":"value0","key1":"value1","key0":"value3"}
I want to store it in a map and the desired result is {"key0":"value3","key1":"value1"}
Using org.json.JsonObject: I passed the string to the constructor and Duplicate key exception is thrown
Using GSON: Same exception when I tried through new Gson.fromJson(string,Type)
Using Jackson: It does work
Is there a workaround to achieve the same using JSONObject and Gson
Interestingly if you first cast that json to an Object and then to a Map<String,String> your desired result happens:
String json = "{\"key0\":\"value0\",\"key1\":\"value1\",\"key0\":\"value3\"}";
Gson gson = new Gson();
Object obj = gson.fromJson(json, Object.class);
try {
Map<String,String> map = (Map<String, String>)obj;
// Outputs...
// key0=value3
// key1=value1
for (Map.Entry<String,String> entry : map.entrySet()) {
System.out.println(entry.getKey() + "=" + entry.getValue());
}
} catch (ClassCastException e) {
e.printStackTrace();
}
GSON uses MapTypeAdapterFactory to deserialioze map. Below is a short excerpt of its source code where a new entry is put in a map:
V replaced = map.put(key, value);
if (replaced != null) {
throw new JsonSyntaxException("duplicate key: " + key);
}
Knowing that there is at least one way to bypass this strict behavior: create your own map that overrides the method put(..) to return always null, like:
public class DuploMap extends HashMap<String, String>{
#Override
public String put(String key, String value) {
super.put(key, value);
return null;
}
}
then deserailizing to it like:
gson.fromJson(JSON, DuploMap.class);
will not throw that exception.
You can use GSON's JsonReader if you do not mind the manual effort.
On the plus side:
faster (no reflection, no casts)
fully under your control
--
String json = "{"key0":"value0","key1":"value1","key0":"value3"}";
JsonReader jsonReader = new JsonReader(new StringReader(json));
HashMap<String,String> map = new HashMap<String, String>()
String currKey;
try {
while(jsonReader.hasNext()){
JsonToken nextToken = jsonReader.peek();
if(JsonToken.NAME.equals(nextToken)){
currKey = jsonReader.nextName();
}
if(JsonToken.STRING.equals(nextToken)){
map.put(currKey, jsonReader.nextString())
}
}
} catch (IOException e) {
e.printStackTrace();
}
Basically I am writing a JSON file using
private void setupDictionaries() {
ObjectMapper mapper = new ObjectMapper();
ArrayNode arrayNode = mapper.createArrayNode();
JsonNode rootNode = mapper.createObjectNode();
ArrayList<String> myThing = new ArrayList<String>();
myThing.add("hi");
myThing.add(".");
itemsDict.put("cake", myThing);
JsonNode childNode1 = mapper.valueToTree(itemsDict);
((ObjectNode) rootNode).set("Jan", childNode1);
JsonNode childNode2 = mapper.createObjectNode();
((ObjectNode) rootNode).set("obj2", childNode2);
JsonNode childNode3 = mapper.createObjectNode();
((ObjectNode) rootNode).set("obj3", childNode3);
String jsonString;
try {
jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
System.out.println(jsonString);
ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter());
writer.writeValue(new File(statsFile), jsonString);
} catch (JsonProcessingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
In this JSON file, I want a similar dictionary generated for all 12 months and load only the one I want to use specifically. However, since these are not simple HashMaps, when I try to load the json file, I get exceptions. Code for loading:
private HashMap<String, List<String>> loadDict() {
ObjectMapper mapper = new ObjectMapper();
try {
HashMap<String, ArrayList<String>> map = mapper.readValue(new File(statsFile), new TypeReference<HashMap<String, ArrayList<String>>>() {});
//Object map = mapper.readValue(new File(statsFile), new TypeReference<Object>() {});
System.out.println(map.get("cake");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Exception:
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.util.HashMap: no String-argument constructor/factory method to deserialize from String value
My JSON file:
{
"Jan" : {
"cake" : [ "hi", "." ]
},
"obj2" : { },
"obj3" : { }
}
EDIT: I think i figured out what causes it
String input = new String(Files.readAllBytes(Paths.get(statsFile)));
System.out.println(input);
String input1 = "{\r\n \"Jan\" : {\r\n \"cake\" : [ \"hi\", \".\" ]\r\n },\r\n \"obj2\" : { },\r\n \"obj3\" : { }\r\n}";
System.out.println(input1);
Running this code, the input is:
"{\r\n \"Jan\" : {\r\n \"cake\" : [ \"hi\", \".\" ]\r\n },\r\n >\"obj2\" : { },\r\n \"obj3\" : { }\r\n}"
{
"Jan" : {
"cake" : [ "hi", "." ]
},
"obj2" : { },
"obj3" : { }
}
(basically reading from a file, all of it is on a single line, where as having the actual json string in an input string its nice and clean, broken up into multiple lines)
Now I only need to figure out how to overcome this...
SOLVED
Rather than writing jsonString to the file, I had to write the rootNode
private void setupDictionaries() {
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer(new DefaultPrettyPrinter());
ArrayNode arrayNode = mapper.createArrayNode();
JsonNode rootNode = mapper.createObjectNode();
ArrayList<String> myThing = new ArrayList<String>();
myThing.add("hi");
myThing.add(".");
itemsDict.put("cake", myThing);
JsonNode childNode1 = mapper.valueToTree(itemsDict);
((ObjectNode) rootNode).set("Jan", childNode1);
JsonNode childNode2 = mapper.createObjectNode();
((ObjectNode) rootNode).set("obj2", childNode2);
JsonNode childNode3 = mapper.createObjectNode();
((ObjectNode) rootNode).set("obj3", childNode3);
String jsonString;
try {
//jsonString = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(rootNode);
System.out.println(rootNode);
writer.writeValue(new File(statsFile), rootNode);
} catch (JsonProcessingException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Which i can simply query by
private HashMap<String, List<String>> loadDict() {
ObjectMapper mapper = new ObjectMapper();
try {
System.out.println("...");
HashMap<String, HashMap<String, ArrayList<String>>> map = mapper.readValue(new File(statsFile), new TypeReference<HashMap<String, HashMap<String, ArrayList<String>>>>() {});
System.out.println(map.get("Jan").get("cake").get(0));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Thanks everyone
Problem is with your TypeReference. Your example JSON is something like HashMap<String, HashMap<String, ArrayList<String>>>
For HashMap<String, ArrayList<String>> JSON should be something like
{ "Jan" : [ "hi", "." ] , "obj2" : [ ], "obj3" : [ ] }
Update:
Test for your example JSON:
public static void main(String[] args) throws JsonParseException, JsonMappingException, IOException {
String input = "{ \"Jan\" : { \"cake\" : [ \"hi\", \".\" ] }, \"obj2\" : { }, \"obj3\" : { } }";
ObjectMapper mapper = new ObjectMapper();
HashMap<String, HashMap<String, ArrayList<String>>> map = mapper.readValue(input,
new TypeReference<HashMap<String, HashMap<String, ArrayList<String>>>>() {
});
System.out.println(map.get("Jan").get("cake").get(0));
}
I have this object:
public class TheObjectToInstantiate{
public String Name;
public String Surname;
public TheObjectToInstantiate(){
}
}
I want to instantiate an array of TheObjectToInstantiate[] with configuration file:
TheObjectToInstantiate1.Name="Pippo"
TheObjectToInstantiate1.Surname="PippoSurname"
TheObjectToInstantiate2.Name="Pluto"
TheObjectToInstantiate2.Surname="PlutoSurname"
I've tried with
public ConfigReader(){
Properties prop = new Properties();
InputStream input = null;
try {
input = new FileInputStream("configuration.prop");
prop.load(input);
Enumeration<?> e = prop.propertyNames();
while (e.hasMoreElements()) {
String key = (String) e.nextElement();
String value = prop.getProperty(key);
......
}
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
scanning all properties and instatiate object manually.
There are ways or open source wrapper to do this without manually compare all properties?
Thanks
It's easier to use json files and deserialize them with libraries like Jackson. You may also check http://www.mkyong.com/java/how-to-convert-java-object-to-from-json-jackson
and How to use Jackson to deserialise an array of objects
public class TheObjectToInstantiate {
public String Name;
public String Surname;
public TheObjectToInstantiate(){}
}
public class JacksonExample {
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
try {
// Convert JSON string from file to Object
TheObjectToInstantiate object = mapper.readValue(new File("G:\\myobject.json"), TheObjectToInstantiate.class);
} catch (IOException e) {
e.printStackTrace();
}
}
json file would be like this:
{
"Name" : "foo",
"Surname" : "bar"
}
you can also deserialize a list of objects:
List<TheObjectToInstantiate> myObjects = mapper.readValue(new File("G:\\myobjectlist.json"), new TypeReference<List<TheObjectToInstantiate>>(){});
[{
"Name" : "foo1",
"Surname" : "bar1"
},
{
"Name" : "foo2",
"Surname" : "bar2"
}]
It also supports more complex structures like nested objects or a List or array of other objects inside your primary object.
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()"
}
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);