I have a simple JSON like this:
{
"enums" : [{"someName" : " someValue ", etc.. }]
}
Sometimes, someValue has whitespace in it. (ie. " someValue ")
I can't seem to get how to SET each value back to the node. I have this:
JsonNode values = root.get("enumValues");
Iterator<Entry<String, JsonNode>> nodes = values.getFields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = (Map.Entry<String, JsonNode>) nodes.next();
// what do I do here?
}
I know that JsonNodes are imutable, but how do I get the JsonObjects? <String, JsonObject> wont work.
I want to be able to parse this as an object (I eventually want to make in recursive for more complex JSON, but one thing at a time) so that when I
print the JSON out it would look like this:
{
"enums" : [{"someName" : "someValue", etc.. }]
}
Given a JSON example
{
"enums" : [{"someName" : " someValue ", "a": " b "}]
}
you can do it like this:
(I also added some code to read the JSON input and to print the JSON output,
and fixed some flaws in your code to make it compilable)
ObjectMapper objectMapper = new ObjectMapper();
File file = new File("example.json");
JsonNode root = objectMapper.readValue(file, JsonNode.class);
ArrayNode arrayNode = (ArrayNode) root.get("enums");
ObjectNode objectNode = (ObjectNode) arrayNode.get(0);
Iterator<Map.Entry<String, JsonNode>> nodes = objectNode.fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = nodes.next();
if (entry.getValue().isTextual()) {
String s = entry.getValue().asText(); // get string from JSON node
s = s.trim(); // remove leading/trailing space
objectNode.put(entry.getKey(), s); // put the string back into JSON node
}
}
objectMapper.writeValue(System.out, root);
Then you get the JSON output
{"enums":[{"someName":"someValue","a":"b"}]}
Related
I'm pretty new to world of jackson, and wanted to read the value of specific field from list of jsons (which is a response body of third-party api).
for a single json, using objectMapper works fine.
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(sampleString);
JsonNode idNode = rootNode.path("id");
System.out.println("id: "+ idNode.asText());
But I want to parse list of jsons (which is a string coming from a response body)
.So for example I receive this body:
[
{
"id":10,
"firstName":"Jack",
"primaryPhone":"9999999999",
"email":"jack#me.com"
},
{
"id":4,
"firstName":"Mark",
"primaryPhone":"9999999991",
"email":"mark#me.com"
},
{
"id":12,
"firstName":"Susaan",
"primaryPhone":"9999999992",
"email":"susan23#me.com"
}
]
I want to read the ids first, and if I find a specific id, return some other info from that block.
For example if id=4, read the firstName and email of that person.
But I'm not sure how to parsee list of json.
Any suggestions/comments is appreciated.
You can try,
JsonNode array = objectMapper.readValue(sampleString, JsonNode.class);
for(int i=0;i<array.length;i++){
JsonNode jsonNode = array.get(i);
JsonNode idNode = jsonNode.get("id");
String id = idNode.asText();
if(id.equals("4")){
JsonNode firstNameNode = jsonNode.get("firstName");
String firstName = firstNameNode.asText();
System.out.println("firstName = " + firstName);
JsonNode emailNode = jsonNode.get("email");
String email = emailNode.asText();
System.out.println("email = " + email);
break;
}
}
You can use Json Path.
So, the query would be something like this:
$[?(#.id == 4)].firstName
You can create a POJO like the one below:
class Record {
private Long id;
private String firstName;
//Getters and setters
}
And deserialise the json into List of these POJOS, e.g.:
ObjectMapper mapper = new ObjectMapper();
List<Record> records = mapper.readValue("", new TypeReference<List<Record>>() { });
Once done, you can filter out the records with stream, e.g.:
List<Record> filtered = records.stream()
.filter(r -> r.getId() = 12)
.collect(Collectors.toList());
I have this json response:
{
"Name": "tardis",
"Driver": "custom",
"Mountpoint": "/var/lib/docker/volumes/tardis/_data",
"Status": {
"hello": "world"
},
"Labels": {
"com.example.some-label": "some-value",
"com.example.some-other-label": "some-other-value"
},
"Scope": "local"
}
From this response, I want to parse the key-value pairs inside "Labels" key. Currently my method to extract those looks like this:
//"json" is the JSON response as a string
ObjectMapper mapper = new ObjectMapper();
JsonNode root = mapper.readTree(json);
Iterator<Entry<String, JsonNode>> it = root.fields();
while (it.hasNext())
{
Map.Entry<String, JsonNode> entry = it.next();
JsonNode n = entry.getValue();
String nlabel = entry.getKey();
if (nlabel != null && nlabel.equals(key))
{
Iterator<Entry<String, JsonNode>> itr = n.fields();
while (itr.hasNext())
{
Map.Entry<String, JsonNode> it2 = itr.next();
String labelKey = it2.getKey();
String labelValue = it2.getValue().toString();
System.out.println();
}
}
}
I am able to retrieve those key value pairs using this logic, but I want to make it simpler because I want to make it work when there is a deeper nesting involved.
Is there a simpler, better way to do it using jackson libs?
DATA1 = {"metrics": {"code1": 0, "code2" : 100} }
DATA2 = {"metrics": {"code1": [10,20,30]}}
CODE
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(m);
JsonNode metric_node = rootNode.path("metrics");
Iterator iterator = metric_node.getFields();
while (iterator.hasNext()) {
logger.info("class_name=> {}", iterator.next().getClass().getName());
logger.info("content=> {}", iterator.next());
}
OUTPUT (for DATA1)
class_name=> java.util.LinkedHashMap$Entry
content=> code1=0
class_name=> java.util.LinkedHashMap$Entry
content=> code2=100
Don't know about DATA2
I am not able to iterate through the hashmap.I tried iterator.next().getKey() etc. but not working. How do I
You are only iterating over the outer keys of the JsonNode you are visiting. And since you are printing out the name of the actual class, that is why you are getting the logged output about the LinkedHashMap$Entry. Take a look at the return type of the metric_node.getFields();
Iterator<Map.Entry<String, JsonNode>> iterator = metric_node.fields();
You are essentially iterating over each node at that level. But since you call iterator.next() twice, you are hitting both keys and the loop is terminating. If you tried to run this code on DATA2, you would get a NoSuchElementException because you are iterating over more items than your iterator actually knows about.
So, you are not actually looking at any of the values associated with those keys. If you change how your loop processes the JsonNodes you will see what keys/values are at each field. If you have nested objects that you wanted to go through, you would need to traverse through each JsonNode
JsonNode rootNode = mapper.readTree(DATA1);
JsonNode metric_node = rootNode.path("metrics");
Iterator<Map.Entry<String, JsonNode>> iterator = metric_node.fields();
while (iterator.hasNext()) {
Map.Entry<String, JsonNode> next = iterator.next();
System.out.println("class_name=> = " + next.getKey());
System.out.println("content=> = " + next.getValue());
System.out.println();
}
Output:
class_name=> = code1
content=> = 0
class_name=> = code2
content=> = 100
I'm using the following code to get JSON data from file, currently I was able to achieve the JSON but in one string. I want to parse it to array. The json file is like this:
{
"employee": [
{
"name": "joan",
"lastname": "test",
"age": 23
},
I'm using the following code to get the data but I get it in one string and I want to print some of the data
JSONObject jsonObject = (JSONObject) parser
.parse(new FileReader("C:\\MockData\\Json\\js.txt"));
JSONParser parser1 = new JSONParser();
ContainerFactory containerFactory = new ContainerFactory() {
public List<?> creatArrayContainer() {
return new LinkedList<Object>();
}
public Map<?, ?> createObjectContainer() {
return new LinkedHashMap<Object, Object>();
}
};
Map<?, ?> json = (Map<?, ?>) parser1.parse(jsonObject.toJSONString(), containerFactory);
Iterator<?> iter = json.entrySet().iterator();
System.out.println("==iterate result==");
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
System.out.println(entry.getKey() + "=>" + entry.getValue());
}
this is the output
employee=[{age=23, name=joan, lastname=test}, {age=22, name=Alex, lastname=avz}, {age=65, name=Dan, lastname=severn}]
Here the entry.getValue() is retuen one concatenated string of the array,
the while is running just one time...
but I want to loop on it to take the key value. How should I do that?
for example if I want to print name alex witn age 22 how should I do that?
Note: The file can be changed so I don't know the keys (now its name but in can be firstName and any other field for that i need generic solution).
if there is a way to use different parser that can do that Im open.
The following is the full solution to your question.
With this code you can break down the data to each employee and also separate the employee attributes.
Set<String> keySet = jsonObject.keySet();
Iterator keySetIterator = keySet.iterator();
while(keySetIterator.hasNext()){
JSONArray array = (JSONArray)jsonObject.get(keySetIterator.next());
while(employeeKeySetIterator.hasNext()){
String employeeKey = employeeKeySetIterator.next().toString();
System.out.println(employeeKey + " : "+ employee.get(employeeKey));
}
}
}
You need to cast the inner json string to a JSONArray
JSONArray array = (JSONArray)jsonObject.get("employee");
Iterator<JSONObject> iterator = array.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next().toString());
}
How can I receive the node names from a JSON tree using Jackson?
The JSON-File looks something like this:
{
node1:"value1",
node2:"value2",
node3:{
node3.1:"value3.1",
node3.2:"value3.2"
}
}
I have
JsonNode rootNode = mapper.readTree(fileReader);
and need something like
for (JsonNode node : rootNode){
if (node.getName().equals("foo"){
//bar
}
}
thanks.
For Jackson 2+ (com.fasterxml.jackson), the methods are little bit different:
Iterator<Entry<String, JsonNode>> nodes = rootNode.get("foo").fields();
while (nodes.hasNext()) {
Map.Entry<String, JsonNode> entry = (Map.Entry<String, JsonNode>) nodes.next();
logger.info("key --> " + entry.getKey() + " value-->" + entry.getValue());
}
This answer applies to Jackson versions prior to 2+ (originally written for 1.8). See #SupunSameera's answer for a version that works with newer versions of Jackson.
The JSON terms for "node name" is "key." Since JsonNode#iterator()
does not include keys, you need to iterate differently:
for (Map.Entry<String, JsonNode> elt : rootNode.fields())
{
if ("foo".equals(elt.getKey()))
{
// bar
}
}
If you only need to see the keys, you can simplify things a bit with JsonNode#fieldNames():
for (String key : rootNode.fieldNames())
{
if ("foo".equals(key))
{
// bar
}
}
And if you just want to find the node with key "foo", you can access it directly. This will yield better performance (constant-time lookup) and cleaner/clearer code than using a loop:
JsonNode foo = rootNode.get("foo");
if (foo != null)
{
// frob that widget
}
fields() and fieldNames() both were not working for me. And I had to spend quite sometime to find a way to iterate over the keys. There are two ways by which it can be done.
One is by converting it into a map (takes up more space):
ObjectMapper mapper = new ObjectMapper();
Map<String, Object> result = mapper.convertValue(jsonNode, Map.class);
for (String key : result.keySet())
{
if(key.equals(foo))
{
//code here
}
}
Another, by using a String iterator:
Iterator<String> it = jsonNode.getFieldNames();
while (it.hasNext())
{
String key = it.next();
if (key.equals(foo))
{
//code here
}
}
Clarification Here:
While this will work:
JsonNode rootNode = objectMapper.readTree(file);
Iterator<Map.Entry<String, JsonNode>> fields = rootNode.fields();
while (fields.hasNext()) {
Map.Entry<String, JsonNode> entry = fields.next();
log.info(entry.getKey() + ":" + entry.getValue())
}
This will not:
JsonNode rootNode = objectMapper.readTree(file);
while (rootNode.fields().hasNext()) {
Map.Entry<String, JsonNode> entry = rootNode.fields().next();
log.info(entry.getKey() + ":" + entry.getValue())
}
So be careful to declare the Iterator as a variable and use that.
Be sure to use the fasterxml library rather than codehaus.
JsonNode root = mapper.readTree(json);
root.at("/some-node").fields().forEachRemaining(e -> {
System.out.println(e.getKey()+"---"+ e.getValue());
});
In one line Jackson 2+