How to remove property fields that ObjectMapper inserts into my JSON Output? - java

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

Related

Parsing Json file and create Hashmap<k,v>

I am finding a solution for get each single key value of a JSONObject dynamicaly.
I have a JSON file like this:
{
"RESPONSE":{
"A":"test",
"B":{
"C":"0",
"D":"1"
},
"E":{
"F":"2",
"G":"3"
}
}
}
I wish to create a Hashmap that contains the key and the value of the objects, like this example:
legend:
key = value
"A" = "test"
"B" = "{"C":"0", "D":"1"}"
"B.C" = "0"
"B.D" = "1"
"E" = "{"F":"2","G":"3"}"
"E.F" = "2"
"E.G" = "3"
I have tried writing this code:
private static HashMap<String, Object> createJsonObjectsHashMapOfConfigFile(String jsonFilePath,
String JsonObjectToIterate) throws Exception {
HashMap<String, Object> jHashMap = new HashMap<>();
JSONObject jsonConfigFile = SimulatorUtil.readJsonFromFile(jsonFilePath); // Returns the Json file
JSONObject jsonConfigObj = jsonConfigFile.getJSONObject(JsonObjectToIterate); // JsonObjectToIterate -->
// "RESPONSE"
Iterator<?> configIter = jsonConfigObj.keys();
String currentDynamicKey = "";
while (configIter.hasNext()) {
currentDynamicKey = (String) configIter.next();
Object currentDynamicValue = jsonConfigObj.get(currentDynamicKey);
jHashMap.put(currentDynamicKey, currentDynamicValue);
logger.info(" ---> " + jHashMap.toString());
}
return jHashMap;
}
but it get only the first level key ("A", "B", "E").
I must use org.json.
Can anyone help me?
Thanks,
Luca

Remove the key-value pairs (nested at any level) from a Json String using LinkedTreeMap

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)));
}

get the size of an array using jackson

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());

Is there any way to put both string and array in single HashMap?

i'm moving from php to Java. and i'm trying to achieve something like below in Java :
$user = array(
"firstname" => "myname",
"lastname" => "surname",
"phone" => array(
"home" => "123213213213",
"office" => "312321321312312",
"mobile" => "4532134213131312"
)
)
is there any way to do like that in java?
Thanks!
There are are few ways to make it closer, but nothing as convenient as that.
Example 1:
Map<String, Object> user = new HashMap<String, Object>() {
{
put("firstname", "myname");
put("lastname", "surname");
put("phone", new HashMap<String, String>() {
{
put("home", "123213213213");
put("office", "312321321312312");
put("mobile", "4532134213131312");
}
});
}
};
Update example:
((Map)user.get("phone")).put("mobile2", "123");
Adding another map:
user.put("address", new HashMap<String, Object>());
(could perhaps be improved by use of putIfAbsent method, or the merge-methods)
Printing current contents:
System.out.println(user);
Gives:
{firstname=myname, address={}, phone={mobile2=123, mobile=4532134213131312, office=312321321312312, home=123213213213}, lastname=surname}
For instance you can use the following code :
Map<String, Object> map = new HashMap<>();
map.put("firstname", "myname");
Map<String, String> phones = new HashMap<>();
phones.put("home" , "123213213213");
phones.put("office" , "312321321312312");
phones.put("mobile" , "4532134213131312");
map.put("phones", phones);
You could use the JSON API in Java to create an object in the format you like. Here is the documentation of the JSON API
http://www.oracle.com/technetwork/articles/java/json-1973242.html
Example:
String stringToParse = "{" +
"firstname: \"myname\"," +
"lastname: \"surname\"," +
"phone: [ " +
" { home: \"123213213213\" }, " +
" { office: \"312321321312312\" }," +
" { mobile: \"4532134213131312\" }" +
"]" +
"}";
JSONParser parser = new JSONParser();
JSONObject json = (JSONObject) parser.parse(stringToParse);
It is "possible" but I don't think it would be good convention (unless there is another way I am unaware of). I believe that this would work:
HashMap<String, Object> hm = new HashMap<String, Object>();
I would think that you would have to use a List object type instead of a array data type for a HashMap. If I were doing this, I would likely create my own class that handles this situation.

How to iterate a JsonObject (gson)

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.

Categories

Resources