I've the below data in a json file.
{
"product":"Data",
"data":{
"zip":[
{
"codeValue":"12345",
"distance":[
{
"5":"a c"
},
{
"2":"z c"
}
]
},
{
"codeValue":"60089",
"distance":[
{
"5":"a c"
},
{
"2":"z c"
}
]
}
]
}
}
and I'm trying to print the zip size using the below code.
public void getJsonResponse() throws Exception {
String text = getTheData();
System.out.println(text);
ObjectMapper objMap = new ObjectMapper();
Map<String, Object> map = objMap.readValue(text, new TypeReference<Map<String, Object>>() {
});
String mainMap = map.get("product").toString();
String getData = map.get("data").toString();
Map<String, Object> map1 = objMap.readValue(getData, new TypeReference<Map<String, Object>>() {
});
List zip = (List) map1.get("zip");
System.out.println(zip.size());
}
here instead of sysout on zip.size(), if I used mainMap, I get the output as Data, but when I use zip.size(), I get some exception as
Exception in thread "main" com.fasterxml.jackson.core.JsonParseException: Unexpected character ('z' (code 122)): was expecting double-quote to start field name
at [Source: java.io.StringReader#60f82f98; line: 1, column: 3]
at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1524)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:557)
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:475)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddName(ReaderBasedJsonParser.java:1293)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._parseName(ReaderBasedJsonParser.java:1190)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:612)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer._readAndBindStringMap(MapDeserializer.java:412)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:312)
at com.fasterxml.jackson.databind.deser.std.MapDeserializer.deserialize(MapDeserializer.java:26)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2993)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2105)
at onlyJava.JsonDataCAll.getJsonResponse(JsonDataCAll.java:24)
at onlyJava.Test.main(Test.java:13)
please let me know where have I gone wrong and how can I fix this.
String getData = map.get("data").toString();
This won't return a JSON to you and hence the exception. You will get something like {zip=[{...
Instead change your statement from
Map<String, Object> map1 = objMap.readValue(getData, new TypeReference<Map<String, Object>>() {
});
to
Map<String, Object> map1 = (Map<String, Object>) map.get("data");
You make conversions that could be skipped. Try this:
Map data = (Map) map.get("data");
List zip = (List) data.get("zip");
System.out.println(zip.size());
cast as ArrayNode
import com.fasterxml.jackson.databind.node.ArrayNode;
ArrayNode zip = (ArrayNode)data.get("zip");
System.out.println(zip.size());
Related
I need to map dynamimc json nested object into hashmap I could come up with solution but I couldn't get expected output.
Here is code
HashMap<String, Object> map = new Gson().fromJson(dynamicJson, HashMap.class);
String keys = map.keySet().stream().collect(Collectors.joining(", "));
String values = map.values().stream().map(obj -> String.valueOf(obj)).collect(Collectors.joining(", "));
System.out.println("Keys: " + keys);
System.out.println("Values: " + values);
Sample Json
{
"name": "Notification 2",
"message": "Facebook",
"tags":[
{
"city" : "Matara",
"village" : "Mirissa"
}
]
}
Actual output :
name, message, tags Notification 2, Facebook, [{city=Matara,
village=Mirissa}]
Expected output
name, message, tags/city, tag/village
Notification 2, Facebook, Matara, Mirissa
In above logic you are not processing sub elements, check below code
HashMap<String, Object> map = new Gson().fromJson(dynamicJson, HashMap.class);
Map<String, String> keyValueMap = new HashMap<>();
map.forEach((key, value) -> {
if (value instanceof List) {
((List)value).stream().forEach(obj -> { // processing sub elements
if (obj instanceof Map) {
((Map)obj).forEach((k,v) -> {
keyValueMap.put(key+"/"+k, v.toString());
});
}
});
} else { // direct value, no subelement
keyValueMap.put(key, value.toString());
}
});
The above logic will work for only elements which are inside List, so you need modify above logic little more generic based on your input json structure.
Below logic is to print the data which can be optimzed , i have written below logic so that it will be easy to understand
keyValueMap.forEach((k, v) -> {
System.out.print(k+ ",");
});
System.out.println();
keyValueMap.forEach((k, v) -> {
System.out.print(v+ ",");
});
it will give out put as below
name,tags/city,message,tags/village,
Notification 2,Matara,Facebook,Mirissa,
Thanks
Prasad
So, I'm encountering this weird problem: I'm using the Woocommerce Rest API and I need to get the src from the "images"-array.
I'v already tried to save the images-array in an other array, but then I have no idea how to get the "src" from the array:
try {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://" + tokens.getShop_name_token() + ".ch/wp-json/wc/v3/products?consumer_key=" + tokens.getConsumer_key_token() + "&consumer_secret=" + tokens.getSecret_key_token());
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String, Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
//JSON Filter
ArrayList<Map<String, String>> myList = (ArrayList<Map<String, String>>) result.get("root");
for (int i = 0; i < myList.size(); i++) {
Map<String, String> dtls = myList.get(i);
productsArr.add(dtls.get("name"));
productStock.add(dtls.get("stock_status"));
productDateCreated.add(dtls.get("date_created"));
//TODO: Filter out image-soure
productImages.add(dtls.get("images"));
}
System.out.println(productImages);
Output: [[], [], [], [{id=16.0, date_created=2018-11-08T15:21:14,
date_created_gmt=2018-11-08T15:21:14,
date_modified=2018-11-08T15:21:14,
date_modified_gmt=2018-11-08T15:21:14,
src=https://website.com/wp-content/uploads/2018/11/1.jpg, name=Vneck
Tshirt, alt=}],
[{id=15.0, date_created=2018-11-08T15:21:14, date_created_gmt=2018-11-08T15:21:14,
date_modified=2018-11-08T15:21:14,
date_modified_gmt=2018-11-08T15:21:14,
src=https://website.com/wp-content/uploads/2018/11/21.jpg,
name=Tshirt, alt=}]]
I got this far. Now my question is: How can I filter out the index to get the "src" of the image?
As you use the rather minimally-featured com.codename1.io.JSONParser JSON parser, which parses JSON to a Map<String, Object> and nothing else, then what you want to do is convert the Object that you get selecting a value to the expected type, and repeat from there.
If the top-level JSON object is an array, then a special "root" element is created, which is what you are getting here. That means that the structure of your JSON is parsed as this:
{
"root": [
{
"name": <str>,
"stock_status": <???>,
"date_created": <str>,
"images":
{
"id": <num>,
"date_*": <str>,
"src": <str>,
"name": <str>,
"alt": <str>
}
]
}
]
}
So, to extract an image's src, you have extracted the "root" array and iterated over it. Instead of casting the results to Map<String, String> however, you want to keep them as Map<String, Object>:
for (const Map<String, Object> element : (List<Map<String, Object>>) result.get("root")) {
// The "element" object has an "images" value that is a list of objects
for (const Map<String, Object> image : (List<Map<String, Object>>) element.get("images")) {
// Save the "src" field of each image
productImages.add((String) image.get("src"));
}
}
I have a Json String representing a object which further has another nested objects. Also, I have a list of keys which I need to remove from this Json String. These keys can be at any nested level of object inside this string. Finally I need to compare this edited Json string to another string and output the differences. I need to remove those key-value pairs from first Json string because I need to ignore those keys during comparison. Currently, I am converting the Json String to LinkedTreeMap provided by Gson API and then doing Map.difference() to compare. Please suggest a solution to this.
I did it by traversing recursively inside the Nested LinkedTreeMap till I find the field and remove it if it exists. The full path of Key needs to be provide to get the exact key-value location inside the Object (like "objects.desc" in the below Json Sample to remove desc from the Json String)
Json Sample:
{
"message": "MSG",
"code": "COD001",
"objects": [
{
"resource": "Student",
"field": "StudentId",
"desc": "Student Description"
}
]
}
Code Sample:
public MapDifference<String, Object> getMapDifference(String jsonString1, String jsonString2) {
MapDifference<String, Object> mapDifference = null;
Gson gson = new Gson();
Type mapType = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> firstMap = gson.fromJson(jsonString1, mapType);
Map<String, Object> secondMap = gson.fromJson(jsonString2, mapType);
firstMap = CollectionUtils.isEmpty(firstMap) ? new HashMap<>() : firstMap;
secondMap = CollectionUtils.isEmpty(secondMap) ? new HashMap<>() : secondMap;
//This contains the List of keys that is required to be filtered out from Json Strings before comparision like {"message", "objects.desc"}
List<String> firstIgnoreList = getIgnoreList1();
List<String> secondIgnoreList = getIgnoreList2();
filterKeys(firstMap, firstIgnoreList);
filterKeys(secondMap, secondIgnoreList);
mapDifference = Maps.difference(firstMap, secondMap);
return mapDifference;
}
private void filterKeys(Map<String, Object> keyMap, List<String> ignoreList) {
if (!(CollectionUtils.isEmpty(keyMap) || CollectionUtils.isEmpty(ignoreList))) {
ignoreList.stream().parallel().forEach(key -> recursiveRemove(keyMap, key));
}
}
private static void recursiveRemove(Map<String, Object> keyMap, String key) {
List<String> path = Arrays.asList(StringUtils.split(key.trim(), "."));
int size = path.size();
int index = 0;
List<LinkedTreeMap> treeMapList = new ArrayList<LinkedTreeMap>();
treeMapList.add((LinkedTreeMap) keyMap);
while (index != size - 1) {
int i = index++;
List<LinkedTreeMap> treeMapListTemp = new ArrayList<LinkedTreeMap>();
treeMapList.stream().parallel().forEach(treeMap -> {
Object obj = treeMap.get(path.get(i));
if (obj instanceof List) {
treeMapListTemp.addAll((List<LinkedTreeMap>) obj);
} else if (obj instanceof LinkedTreeMap) {
treeMapListTemp.add((LinkedTreeMap) obj);
}
});
treeMapList = treeMapListTemp;
}
treeMapList.stream().parallel().forEach(treeMap -> treeMap.remove(path.get(size - 1)));
}
I'm trying to create complex JSon output file with some data(HashTable collections in one big) and got some error on serializing the output. After some investigation found that need to set Visibility to these property fields and now i see strange values for HastTable in my output, that actually i don't need them. Here is some code:
PrintWriter out = null;
Map<String, String> hm = new HashMap<String, String>();
Map<String, String> hmReqMap = new HashMap<String, String>();
Map<String, String> hmResMap = new HashMap<String, String>();
Map<String, String> hmGate = new HashMap<String, String>();
Map<String, String> hmResult = new HashMap<String, String>();
JSONArray ja = new JSONArray();
JSONObject mainObj = new JSONObject();
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
try {
File file = new File(outputDirectory + File.separator + "aaa" + IConst.JSON_EXTENSION);
out = new PrintWriter(new BufferedWriter(new FileWriter(file, true)));
if (tcStats != null) {
for (SingleTest singleTest : tcStats.getTestsList()) {
Map<String, String> reqMap = new HashMap<String, String>();
Map<String, String> resMap = new HashMap<String, String>();
SomeClassAllDetails allDdetails = singleTest.getSiteTransaction();
for (Entry<String, String> entry : allDetails.getEPowerEntries().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (key.startsWith("req.")) {
reqMap.put(key.substring(4), value);
} else if (key.startsWith("res.")) {
resMap.put(key.substring(4), value);
}
}
hmGate.put("Gate", singleTest.getGate().toString());
hmReqMap.put("Request", reqMap.toString().substring(1, reqMap.toString().length() - 1));
hmResMap.put("Response", resMap.toString().substring(1, resMap.toString().length() - 1));
hmResult.put("Result", singleTest.getComparisonResult().toString());
hm.putAll(hmGate);
hm.putAll(hmReqMap);
hm.putAll(hmResMap);
hm.putAll(hmResult);
ja.put(hm);
mainObj.put(singleTest.getLabel(), ja);
}
String mapAsJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mainObj);
out.println(mapAsJson);
out.println(",");
} else if ("opening".equals(type)) {
out.println("{");
} else if ("closing".equals(type)) {
out.println("}");
}
That's the actually output and as you can see the keys like map,myArrayList are added here:
{
"map" : {
"Tran_ID" : {
"myArrayList" : [ {
"map" : {
"Response" : "value1=333333 value2=33333, value4=5555",
"Request" : "value6=44444, value7=000000",
"Gate" : "10.0.0.1",
"Result" : "Done"
}
} ]
}
}
}
How do i remove them?
If i remove the following code
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);
then i got error that i need to disable SerializationFeature.FAIL_ON_EMPTY_BEANS
My goal is to create this Json Output:
{
"Tran_ID" : [{
"Response" : "value1=333333 value2=33333, value4=5555",
"Request" : "value6=44444, value7=000000",
"Gate" : "10.0.0.1",
"Result" : "Done"
}]
}
OK, here is a solution:
Go to http://www.jsonschema2pojo.org/ (NB: I'm not affiliated with this site, it's just a handy tool)
Select "Source type": "JSON" and you correct jackson version below. Also uncheck "Allow additional properties" (on the the right)
Copy/paste your wanted JSON on the left big text box.
Clic on preview at the bottom, this will generates your java classes.
Next step is to "fill" a class instance with your data
Sample "filling" code (with generated classes name):
TranID tranId = new TranID(); // {}
tranId.setResponse("value1=333333, value2=33333, value4=5555"); // { "Response": ... }
tranId.setRequest("value6=44444, value7=000000"); // { "Response": ..., "Request": ... }
tranId.setGate("10.0.0.1"); // etc
tranId.setResult("Done")
Example example = new Example(); // { "tranID": undefined }
example.setTranId(new ArrayList<>()); // { "tranID": [] }
example.getTranId().add(tranId); // { "tranID": [{ "Response": ..., "Request": ... }] }
// output
String json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(example);
Thanks for your help, but it didn't really help to problem
and I rewrote the code and put this one:
String jo = Json.createObjectBuilder()
.add(singleTest.getLabel(), Json.createObjectBuilder()
.add("Request", reqMap.toString().substring(1, reqMap.toString().length() - 1))
.add("Response", resMap.toString().substring(1, resMap.toString().length() - 1))
.add("Result", singleTest.getComparisonResult().toString())
.add("Gate", singleTest.getGate().toString()))
.build().toString();
You should also add to pom.xml these dependencies:
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.0.4</version>
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.0</version>
And then you can do whatever you want with you string.
Thanks
I have a JsonObject e.g
JsonObject jsonObject = {"keyInt":2,"keyString":"val1","id":"0123456"}
Every JsonObject contains a "id" entry, but the number of other key/value pairs is NOT determined, so I want to create create an object with 2 attributes:
class myGenericObject {
Map<String, Object> attributes;
String id;
}
So I want my attributes map to look like this:
"keyInt" -> 4711
"keyStr" -> "val1"
I found this solution
Map<String, Object> attributes = new HashMap<String, Object>();
Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for(Map.Entry<String,JsonElement> entry : entrySet){
attributes.put(entry.getKey(), jsonObject.get(entry.getKey()));
}
but the values are enclosed by ""
"keyInt" -> "4711"
"keyStr" -> ""val1""
How to get the plain values (4711 and "val1")?
Input data:
{
"id": 0815,
"a": "a string",
"b": 123.4,
"c": {
"a": 1,
"b": true,
"c": ["a", "b", "c"]
}
}
or
{
"id": 4711,
"x": false,
"y": "y?",
}
replace "" with blank.
Map<String, Object> attributes = new HashMap<String, Object>();
Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for(Map.Entry<String,JsonElement> entry : entrySet){
if (! nonProperties.contains(entry.getKey())) {
properties.put(entry.getKey(), jsonObject.get(entry.getKey()).replace("\"",""));
}
}
How are you creating your JsonObject? Your code works for me. Consider this
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
...
...
...
try{
JsonObject jsonObject = new JsonObject();
jsonObject.addProperty("keyInt", 2);
jsonObject.addProperty("keyString", "val1");
jsonObject.addProperty("id", "0123456");
System.out.println("json >>> "+jsonObject);
Map<String, Object> attributes = new HashMap<String, Object>();
Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for(Map.Entry<String,JsonElement> entry : entrySet){
attributes.put(entry.getKey(), jsonObject.get(entry.getKey()));
}
for(Map.Entry<String,Object> att : attributes.entrySet()){
System.out.println("key >>> "+att.getKey());
System.out.println("val >>> "+att.getValue());
}
}
catch (Exception ex){
System.out.println(ex);
}
And it is working fine. Now I am interested in knowing how you created that JSON of yours?
You can also try this (JSONObject)
import org.json.JSONObject;
...
...
...
try{
JSONObject jsonObject = new JSONObject("{\"keyInt\":2,\"keyString\":\"val1\",\"id\":\"0123456\"}");
System.out.println("JSON :: "+jsonObject.toString());
Iterator<String> it = jsonObject.keys();
while( it.hasNext() ){
String key = it.next();
System.out.println("Key:: !!! >>> "+key);
Object value = jsonObject.get(key);
System.out.println("Value Type "+value.getClass().getName());
}
}
catch (Exception ex){
System.out.println(ex);
}
Just make following changes...
Map<String, Object> attributes = new HashMap<String, Object>();
Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for(Map.Entry<String,JsonElement> entry : entrySet){
attributes.put(entry.getKey(), jsonObject.get(entry.getKey()).getAsString());
}
"getAsString" will do the magic for u
Your Map values are JsonElements. Whenever you print a JsonElement (e.g. using a debugger) its toString() method will be called - and since a JsonElement has many implementing classes the default toString implementation wraps the value in quotes to ensure correct JSON. To get the value as a normal, unwrapped String, simply call getAsString():
JsonElement elem;
// ...
String value = elem.getAsString();
With your example:
Map<String, Object> attributes = new HashMap<String, Object>();
Set<Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
for(Map.Entry<String,JsonElement> entry : entrySet){
attributes.put(entry.getKey(), jsonObject.get(entry.getKey()).getAsString());
}
Note there are many other methods you can call on a JsonElement to produce other types.
I am not quite sure why you want to do manual manipulation in the first place. GSON decode will simply leave those absent key/value pairs as default value (zero,null). And then you can process as you want.