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));
}
Related
I have a case to transform a response from
Dogs API
to a different structure like this :
[
{
"breed": "pug",
"sub_breed": []
},
{
"breed": "ridgeback",
"sub_breed": [
{
"breed": "rhodesian",
"sub_breed": []
}
]
},
{
"breed": "doberman",
"sub_breed": []
},
{
"breed": "hound",
"sub_breed": [
{
"breed": "Ibizan",
"sub_breed": []
},
{
"breed": "afghan",
"sub_breed": []
}
]
}
]
I am confused after getting the response and don't know how to transform it.
Here is what I do until getting the response
public List<DogResponse> getDogs() {
List<DogResponse> response = new ArrayList<DogResponse>();
try {
String url = "https://dog.ceo/api/breeds/list/all";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
ObjectMapper mapper = new ObjectMapper();
Map<String, String> map = mapper.readValue(result.getBody().toString(), Map.class);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map.get("message")));
for (Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println("key : "+key);
System.out.println("val : "+value);
}
} catch (Exception e) {
// TODO: handle exception
}
return response;
}
DogResponse
public class DogResponse {
private String breed;
private DogResponse sub_breed;
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public DogResponse getSub_breed() {
return sub_breed;
}
public void setSub_breed(DogResponse sub_breed) {
this.sub_breed = sub_breed;
}
}
I am trying using Map but failed when I want to print the key and value, it's showing nothing.
You should map the response to List of DogResponse you may have an issue because of circular dependency.
List<DogResponse> dogs = mapper.readValue(jsonString, new TypeReference<List<DogResponse>>() {});
You can try this.
public List<DogResponse> getDogs() {
List<DogResponse> response = new ArrayList<DogResponse>();
try {
String url = "https://dog.ceo/api/breeds/list/all";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.getForEntity(url, String.class);
ObjectMapper mapper = new ObjectMapper();
Map<String, Map<String, List<String>>> map = mapper.readValue(result.getBody().toString(), Map.class);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map.get("message")));
Map<String, List<String>> innerMap = map.get("message");
for (Entry<String, List<String>> entry : innerMap.entrySet()) {
String key = entry.getKey();
List<String> value = entry.getValue();
System.out.println("key : " + key);
System.out.println("val : " + value);
}
} catch (Exception e) {
// TODO: handle exception
}
return response;
}
ResponseEntity result = restTemplate.getForEntity(url, DogResponse.class);
This should work.
I have a json as below. I want to get mobile_number from this jsonObject.
json:-
{"id": "ABCD", "report": { "data": { "phone": { "mobile_number": 9876543210, "active": "Y", "content": null } } } }
I am doing it like this and it works fine but can someone help me with any other approach for it without getting every key.
JSONObject jsonObject = new JSONObject(json);
JSONObject report = getJSONObjectFromJson(jsonObject, "report");
JSONObject data = getJSONObjectFromJson(jsonObject, "data");
JSONObject phone = getJSONObjectFromJson(data, "phone");
long mobileNumber = getLongFromJson(phone, "mobile_number");
private Long getLongFromJson(JSONObject object, String key){
return (object !=null && object.has(key)) ? object.getLong(key) : null;
}
private JSONObject getJSONObjectFromJson(JSONObject object, String key){
return (object !=null && object.has(key)) ? object.getJSONObject(key) : null;
}
I've just dealing with the similar issue and decided to use JsonPath like this:
final DocumentContext jsonContext = JsonPath.parse(jsonString);
final Object read = jsonContext.read("$['report']['data']['phone']['mobile_number']");
You can use Jackson ObjectMapper.
try {
ObjectMapper mapper = new ObjectMapper();
String jsonString = "{\"id\": \"ABCD\", \"report\": { \"data\": { \"phone\": { \"mobile_number\": 9876543210, \"active\": \"Y\", \"content\": null } } } }";
JsonNode rootNode = mapper.readTree(jsonString);
JsonNode mobileNumber = rootNode.path("report").path("data").path("phone").path("mobile_number");
System.out.println("Mobile Number: " + mobileNumber.longValue());
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
So there are lot of ways to do it but everything leads eventually to traversing the tree.
So to conclude all the approaches,
1. **Convert string to JsonObject and traverse.**
JSONObject jsonObject = new JSONObject(json);
JSONObject report = getJSONObjectFromJson(jsonObject, "report");
JSONObject data = getJSONObjectFromJson(jsonObject, "data");
JSONObject phone = getJSONObjectFromJson(data, "phone");
long mobileNumber = getLongFromJson(phone, "mobile_number");
private Long getLongFromJson(JSONObject object, String key){
return (object !=null && object.has(key)) ? object.getLong(key) : null;
}
private JSONObject getJSONObjectFromJson(JSONObject object, String key){
return (object !=null && object.has(key)) ? object.getJSONObject(key) : null;
}
2. **Using jackson objectMapper to get the JsonNode and then traverse.**
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode= mapper.readTree(json);
JsonNode mobileNumber = jsonNode.path("report").path("data").path("phone").path("mobile_number");
3. **Using gson jsonmapper to convert to map and then iterate the map.**
Gson gson = new Gson();
Map map = gson.fromJson(json, Map.class);
jsonObject.getJSONObject("x").getJSONObject("Y").getJSONObject("z");
Another route would be to leverage the ObjectMapper.
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
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();
}
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()"
}