I don't know a ton about Jackson, I'm just using it because I needed to share data from Python to Java. Anyway my code is pretty simple
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> data = mapper.readValue(new File(FileName), Map.class);
System.out.println(data.get("SomeInput"));
This is what I'm getting:
{Y=0.830168776371308, Z=0.16877637130801687, X=0.0010548523206751054}
I really just want to be able to use data to retrieve some type of data structure that holds the data without printing out the {} and the =, etc. Is there a method to do this?
I have a group of nodes, one node for each tag (such as ADP). I want to be able to give the ADP node 0.830... I can do this with the string, but it would involve some really annoying splitting of Strings. I'm assuming there must be an easy way to do this?
EDIT:
The data in the json file that I'm loading looks like this
{
"!": {
"X": 1.0
},
"$": {
"X": 1.0
},
"&": {
"X": 1.0
},
"/m": {
"Y": 1.0
},
.....
ObjectMapper mapper = new ObjectMapper();
Map<String,Object> data = mapper.readValue(new File(FileName), Map.class);
Map<String, Double> tags = (Map) data.get("SomeInput");
double value = 0;
for (String tag : tags.keySet()) {
value = tags.get(tag); //Here I get all the data from the tags inside the input. E.g.: 0.830168776371308
System.out.println(value); //It will print ADP, ADV and X values.
}
You already got a good answer on how to use Map. But for sake of completeness, there is another possibility that sometimes works even better, reading as a tree:
JsonNode root = mapper.readTree(new File(FileName));
JsonNode inputs = root.path("SomeInput");
String exclValue = inputs.path("!").asString();
Related
I have been combing over multiple approaches with different JSON libraries, and cannot seem to find an elegant way to convert to and from with my JSON file in testing.
JSON file looks like this:
[
{
"LonelyParentKey": "Account",
"ProcessNames": [
{"Name": "ProcessOne",
"Sequence": "1"
},
{
"Name": "ProcessTwo",
"Sequence": "2"
},
{
"Name": "ProcessThree",
"Sequence": "3"
},
{
"Name": "ProcessFour",
"Sequence": "4"
}
]
}
]
In a QAF-based test using TestNG, am trying to import the values of the "ProcessName" key like this:
String lonelyParentKey = (String) data.get("LonelyParentKey");
ArrayList processNames = (ArrayList) data.get("ProcessNames");
I've seen that in the framework I'm using, I have multiple JSON library options, have been trying to use GSON after reading other SO posts.
So, next in the test code:
Gson gson = new Gson();
JSONArray jsa = new JSONArray(processNames);
What I am attempting to to create an object that contains 4 child objects in a data structure where I can access the Name and Sequence keys of each child.
In looking at my jsa object, it appears to have the structure I'm after, but how could I access the Sequence key of the first child object? In the REPL in IntelliJ IDEA, doing jsa.get(0) gives me "{"Name": "ProcessOne","Sequence": "1"}"
Seems like a situation where maps could be useful, but asking for help choosing the right data structure and suggestions on implementing.
TIA!
Not sure which library you're using, but they all offer pretty much the same methods. JSONArray looks like org.json.JSONArray, so that would be
JSONArray jsa = new JSONArray(processNames);
int sequenceFirstEntry = jsa.getJSONObject(0).getInt("Sequence");
Some JsonArray implementations also implement Iterable, then this also works
JSONArray jsa = new JSONArray(processNames);
for (JSONObject entry : jsa) {
int sequenceFirstEntry = entry.getInt("Sequence");
}
Any reason to not use DTO classes for your model?
e.g.
class Outer {
String lonelyParentKey;
List<Inner> processNames;
// getter/setter
}
and
class Inner {
String name;
String sequence;
// getter/setter
}
now your library should be able to deserialize your JSON string into a List. I have been using Jackson instead of GSON, but it should be similar in GSON:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
List<X> x = objectMapper.readValue(json, new TypeReference<List<X>>() {});
My Json is like this
{
"A1":"1234",
"A2": "123",
"A3": "???",
"A4": "object, may not be populated.",
"A5": { },
"A6": { },
"A7":{
"B1": ["100"],
"B2": ["C"],
"B3": ["O", "A"]
},
"A8":{
"B4":["D1"],
"B5":["D2"],
"B6":["D3"],
"B7":["D4"],
"B8":["D5"],
"B9":["D6"],
"B10":["123"]
}
"ignoreThisField": "it is useless"
}
I am using Jackson library. I want to edit let's say element B4, which is inside A8 and it is of array type.
I tried below code
byte[] jsonData = readJson(JsonFilePath);
// Convert json String to object
POJOClass pojo= getValue(jsonData, POJO.class);
objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true)
.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES, true);
JsonNode rootNode = objectMapper.readTree(jsonData);
// ((ObjectNode) rootNode).put("B4", "A" + "Somedata");
But it gives me output as
"B4":"[Somedata]"
instead of
"B4":["Somedata"]
which results in unexpected result.
B4 node contains list of data. How can we edit a node which is type array.
If we can not achieve this using jackson then is there any other library which can solve the problem?
I tried below links
Modify JsonNode of unknown JSON dynamically in Java and How to retrieve and update json array element without traversing entire json
but could not achieve much out of it
If i am not wrong you want to modify the B4 object present in the JSON data. To correctly do it you should use the below code.
JsonNode node = rootNode.get("A8");
List<String>list = new ArrayList<String>();//create a ArrayList
list.add("Anything"); //add data to arraylist
ArrayNode arrayNode = ((ObjectNode)node).putArray("B4"); //add the arraydata into the JSONData
for (String item : list) { //this loop will add the arrayelements one by one.
arrayNode.add(item);
}
you not using jackson lib fully.
<YOur pojo object> mypojo =objectMapper.readValue(jsonData, <yourpojo.class>);
now you can just use getter setter
I have a really complicated nested json whose structure is always changing. I want to parse it in JAVA such that I can retrieve any element using the key/field name.
Option 1 - The easiest way to do this would be to convert/parse the json into a JAVA object.
I have tried everything (gson, JSONObject, Jackson...) But I cant convert the json unless I have a java class ready and since the json doesn't follow a fixed structure I cant convert it into a JAVA class. Is there any other library that can convert the json to a java object? (Without the need for a pre existing java class to convert the json into)
Option 2 - Or is there a way/library I can use, which if given a portion of the json, the program prints all the elements in the json file. Something like this...
StreetAddressLine
PrimaryTownName : value
CountryISOAlpha2Code :value
TerritoryAbbreviatedName :value
PostalCode : value
{"PrimaryAddress": [ {
"StreetAddressLine": [{"LineText": "492 Koller St"}],
"PrimaryTownName": "San Francisco",
"CountryISOAlpha2Code": "US",
"TerritoryAbbreviatedName": "CA",
"PostalCode": "94110",
"AddressUsageTenureDetail": [{"TenureTypeText": {
"#DNBCodeValue": 1129,
"$": "Rents"
}}],
"PremisesUsageDetail": [{"PremisesUsageFunctionDetail": [{"PremisesFunctionText": {
"#DNBCodeValue": 12058,
"$": "Manufacturing"
}}]}],
"CountyOfficialName": "San Francisco County",
"TerritoryOfficialName": "California",
"CountryGroupName": "North America",
"GeographicalPrecisionText": {
"#DNBCodeValue": 0,
"$": "Unknown"
},
"UndeliverableIndicator": false,
"MetropolitanStatisticalAreaUSCensusCode": ["San Francisco-Oakland-Hayward CA"],
"RegisteredAddressIndicator": false,
"ResidentialAddressIndicator": false
}]}
Thanks a lot!
Try using json-simple to parse the JSON into a bunch of nested JSONObject (which basically are maps) and JSONArray (which basically are lists) elements and extract the values yourself.
Just a node: PrimaryAddress indicates that there might be a SecondaryAddress as well, so the nesting should not change, otherwise it might be hard to determine things like which address StreetAddressLine belongs to.
In that case the better question would be: why does the structure change that often?
Ok I found a solution! I used the Jackson Parser
First map your jsonString to a JsonNode
JsonNode rootNode = mapper.readValue(jsonString, JsonNode.class);
Update the rootNode to contain the json for the required key:
rootNode = rootNode.findParent(key);
and then depending on if it is an array or a list handle it seperately:
if(rootNode.path(key).isArray()){
//key is the field in the json that you might be looking for
for (final JsonNode objNode : rootNode) {
for (Iterator<String> keyArray = objNode.getFieldNames(); keyArray.hasNext();){
fieldName = keyArray.next();
fieldValue = objNode.path(fieldName).asText();
if(fieldValue != ""){
System.out.println(fieldName + " = " + fieldValue);
}else{
arrayHandler(objNode,fieldName);
}
}
}
At each iteration check if the resulting JsonNode is an array or a list.
If it is a List handle it differently (Just iterate over the key value pairs like this)
for (Iterator<String> keyArray = rootNode.getFieldNames(); keyArray.hasNext();){
fieldName = keyArray.next();
fieldValue = rootNode.get(fieldName).asText();
System.out.println(fieldName + " = " + fieldValue);
}
After every iteration check what the next jsonNode is and call the respective handler recursively...
I have a map of JSON objects as follows:
Map<String,Object> map = HashMap<String,Object>();
map.put("first_name", "prod");
JSONObject jsonObj = new JSONObject("some complex json string here");
map.put("data", jsonObj);
Gson gson = new Gson();
String result = gson.toJson(map);
Now if the "some complex JSON string here" was:
{"sender":{"id":"test test"},"recipients":{"id":"test1 test1"} }
and execute above code gives me something like:
{
"first_name": "prod",
"data": {
"map": {
"sender": {
"map": {
"id": "test test"
}
}
},
"recipients": {
"map": {
"id": "test1 test1"
}
}
}
}
}
I might have some syntax error up there, but basically I don't know why I am seeing objects wrapped around map's.
Update
according to comments, it is a bad idea to mix different json parsers.
i can understand that. but my case requires calling an external api which takes a hash map of objects that are deserialized using gson eventually.
is there any other object bedsides JSONObject that i can add to the map and still have gson create json out of it without extra 'map' structure? i do understand that i can create java beans and achieve this. but i'm looking for a simpler way since my data structure can be complex.
Update2
going one step back, i am given a xml string. and i have converted them to json object.
now i have to use an external api that takes a map which in turn gets converted to json string using gson in external service.
so i am given an xml data structure, but i need to pass a map to that function. the way i have described above produces extra 'map' structures when converted to json string using gson. i do not have control to change how the external service behaves (e.g. using gson to convert the map).
Mixing classes from two different JSON libraries will end in nothing but tears. And that's your issue; JSONObject is not part of Gson. In addition, trying to mix Java data structures with a library's parse tree representations is also a bad idea; conceptually an object in JSON is a map.
If you're going to use Gson, either use all Java objects and let Gson convert them, or use the classes from Gson:
JsonObject root = new JsonObject();
root.addProperty("first_name", "prod");
JsonElement element = new JsonParser().parse(complexJsonString);
root.addProperty("data", element);
String json = new Gson().toJson(root);
This has to do with the internal implementation of JSONObject. The class itself has an instance field of type java.util.Map with the name map.
When you parse the String
{"sender":{"id":"test test"},"recipients":{"id":"test1 test1"} }
with JSONObject, you actually have 1 root JSONObject, two nested JSONObjects, one with name sender and one with name recipients.
The hierarchy is basically like so
JSONObject.map ->
"sender" ->
JSONObject.map ->
"id" -> "test test",
"recipients" ->
JSONObject.map ->
"id" -> "test test1"
Gson serializes your objects by mapping each field value to the field name.
Listen to this man.
And this one.
I'd a similar problem and I finally resolved it using json-simple.
HashMap<String, Object> object = new HashMap<String,Object>;
// Add some values ...
// And finally convert it
String objectStr = JSONValue.toJSONString(object);
You may try out the standard implementation of the Java API for JSON processing which is part of J2EE.
JsonObject obj = Json
.createObjectBuilder()
.add("first_name", "prod")
.add("data", Json.createObjectBuilder()
.add("sender", Json.createObjectBuilder().add("id", "test test"))
.add("recipients", Json.createObjectBuilder().add("id", "test1 test1"))).build();
Map<String, Object> prop = new HashMap<String, Object>() {
{
put(JsonGenerator.PRETTY_PRINTING, true);
}
};
JsonWriter writer = Json.createWriterFactory(prop).createWriter(System.out);
writer.writeObject(obj);
writer.close();
The output should be:
{
"first_name":"prod",
"data":{
"sender":{
"id":"test test"
},
"recipients":{
"id":"test1 test1"
}
}
}
I have data that looks like this
{
"status": "success",
"data": {
"data1": {
"serialNumber": "abc123",
"version": "1.6"
},
"data2": {
"irrelvent": [
"irrelvent",
"irrelvent"
]
},
"data3": {
"irrelevantLibs": {
"irrelevantFiles": [
"irrelevant.jar",
"irrelevant.jar",
"irrelevant.jar"
]
}
},
"data4": {
"configuration": "auth"
}
}
}
I am using the Jackson JSON Processor. What I need to do under the data object is to extract each data(x) into it's own data.
Hard to explain but I will try to be detailed. My intent is to make the JSON data more readable for our customers. So I'm trying to make the JSON data more friendly by splitting each data(x) object into blocks/tables on a website. So data1 will be displayed independently. Then data2 will be displayed independently and so on. So in this case I have four data(x) objects and I want to store those four objects into four different Strings and display them however I want. My problem is how do I get the Jackson Processor to do this?
Not sure if this is helpful but my current JSON function to process the JSON data is this:
public static String stringify(Object o) {
try {
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
return mapper.writer(printer).writeValueAsString(o);
} catch (Exception e) {
return null;
}
}
I'm positive that I can manipulate the processor to get those data separated but I don't know where to start.
EDIT: Hmm, since Jackson seems to be a pretty difficult parser to work with, would it be easier if I used the Javascript JSON parser to extract only the data objects? Since I already have Jackson convert the JSON data into a String, using Javascript would work?
"Hmm, since Jackson seems to be a pretty difficult parser to work with, would it be easier if I used the Javascript JSON parser to extract only the data objects?"
Seeing as you are working with Java have you considered using Sling? http://sling.apache.org/ It is an external library which will allow you parser and explore JSON data structures quite swiftly, and most of all cleanly.
So I was able to figure it out after really digging into the documentation. I had to use JsonNode in order to extract what I wanted. Note that the variable appName is just there for me to easily display the string data(x) while iteNode is just all elements under data(x)
public static List<String> jsonSplit(String o) throws JsonParseException, JsonMappingException, IOException {
List<String> list = new ArrayList<String>();
ObjectMapper mapper = new ObjectMapper();
DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
printer.indentArraysWith(new Lf2SpacesIndenter());
JsonNode rootNode = mapper.readValue(o, JsonNode.class);
Iterator<String> appName = rootNode.get("data").getFieldNames();
Iterator<JsonNode> iteNode = rootNode.get("data").getElements();
while (iteNode.hasNext()){
list.add(appName.next());
list.add(mapper.writer(printer).writeValueAsString(iteNode.next()));
}
return list;
}