Get nested JSON elements from ObjectNode using Jackson - java

I have an ObjectNode, that looks as follows
{
"Header":{
"sub-header1":{
"#field":"value",
"#field":"value",
},
"sub-header2":{
"field":"",
"field":"",
"field":"",
"panel_field":{
"value":"",
"value":""
}
}
}
Now, what I want to do is to get all the fields from sub-headers in a list. This is the method that I'm employing
public static List<String> getDocumentFields(ObjectNode jsonDocumentNode) {
List<String> documentFields = new ArrayList<>();
Iterator<JsonNode> fields = jsonDocumentNode.elements();
while (fields.hasNext()) {
JsonNode jsonNode = fields.next();
Iterator<Map.Entry<String, JsonNode>> jsonFields = jsonNode.fields();
while (jsonFields.hasNext()) {
Map.Entry<String, JsonNode> jsonNodeEntry = jsonFields.next();
documentFields.add(jsonNodeEntry.getKey());
}
}
return documentFields;
}
But, I'm only getting headers in the list like {sub-header1, sub-header2}, instead of fields. How can I fix this? I'd really appreciate any kind of help.
EDIT:
While #sfiss's answer helped a great deal, I still wanted to find a way to do so without hardcoding the loop-logic and this answer turned out to be the exact thing I was looking for.

Well, it's simple, you are not iterating deep enough (field list is on third level). If you know the structure of your JSON, just iterate until you find the desired fields:
public class MyTest {
#Test
public void testJson() throws IOException {
final String json = getJson();
final JsonNode jsonDocumentNode = new ObjectMapper().readTree(json);
final List<String> fields = getDocumentFields((ObjectNode) jsonDocumentNode);
assertThat(fields, Matchers.contains("#field1", "#field2", "field1", "field2", "field3", "panel_field"));
}
public static String getJson() {
return "{\r\n" +
" \"Header\":{\r\n" +
" \"sub-header1\":{\r\n" +
" \"#field1\":\"value\",\r\n" +
" \"#field2\":\"value\"\r\n" +
" },\r\n" +
" \"sub-header2\":{\r\n" +
" \"field1\":\"\",\r\n" +
" \"field2\":\"\",\r\n" +
" \"field3\":\"\",\r\n" +
" \"panel_field\":{\r\n" +
" \"value1\":\"\",\r\n" +
" \"value2\":\"\"\r\n" +
" }\r\n" +
" } \r\n" +
" }\r\n" +
"}";
}
public static List<String> getDocumentFields(final ObjectNode jsonDocumentNode) {
final List<String> documentFields = new ArrayList<>();
for (final JsonNode header : (Iterable<JsonNode>) jsonDocumentNode::elements) {
for (final JsonNode subheader : (Iterable<JsonNode>) header::elements) {
for (final Map.Entry<String, JsonNode> field : (Iterable<Map.Entry<String, JsonNode>>) subheader::fields) {
documentFields.add(field.getKey());
}
}
}
return documentFields;
}
}
However, I would argue that it is simpler to let jackson serialize the JSON into a convenient data structure, and you just use the POJO's getters to obtain your values. That would also make it more clear than handling the JsonNode.
Just FYI, I edited your JSON slightly and used Java 8 SAM conversions to create iterables for the foreach-loops from the iterators, but you can still use your code and iterate one more level using while and iterators.

Related

Get constructor for Deserialization basis the Environment selected

I am trying to deserialize a JSON file basis the environment selected by the user . My requirement is to select data fro JSON basis the Environment selected & convert them into Java Object for running my test script . Below is the research I could comup with so far .
JSON file //Select the JSON array basis the environment(QA,STAGE)
{
"QA":{
"customerName":"Customer QA",
"customerAddr":"UK",
"currency": "GBP"
},
"STAGE" : {
"customerName":"Customer STAGE",
"customerAddr":"FRANCE",
"currency": "EUR"
}
}
Java Class //Class to transform JSON to Object . Call the constructor of the class basis the environment (QA,STAGE)
public class P {
String customerName;
String customerAddr;
String currency;
P(String env,String customerName,String customerAddr,String currency)
{
if(env.equals("qa"){}
if(env.equals("stage"){}
}
Deserialization Class // Need to decide how to call the above class constructor basis the environment for deserializing
public static <T> T deserializeJson(String fileName, Class<T> T) throws IOException {
InputStream is = JacksonUtils.class.getClassLoader().getResourceAsStream(fileName);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(is, T);
}```
There seem to be multiple possible solutions for this. However, without knowing what you want to with it afterwards, its not really possible to tell which is best.
Personally I would make an additional class which holds the environments, as there should be a finite number of environments (currently we know about 2).
#Data
class Environment {
#JsonProperty(value = "QA")
UserData qa;
#JsonProperty(value = "STAGE")
UserData stage;
}
And UserData is your P:
#Data
class UserData {
String customerName;
String customerAddr;
String currency;
}
Then you can parse it like this:
String json = "{\n" + "\"QA\":{\n" + " \"customerName\":\"Customer QA\",\n"
+ " \"customerAddr\":\"UK\",\n" + " \"currency\": \"GBP\"\n" + " },\n"
+ "\"STAGE\" : {\n" + " \"customerName\":\"Customer STAGE\",\n"
+ " \"customerAddr\":\"FRANCE\",\n" + " \"currency\": \"EUR\"\n" + "}\n"
+ "}";
ObjectMapper objectMapper = new ObjectMapper();
Environment environment = objectMapper.readValue(json, Environment.class);
System.out.println(environment);
Which prints:
Environment(qa=UserData(customerName=Customer QA, customerAddr=UK, currency=GBP), stage=UserData(customerName=Customer STAGE, customerAddr=FRANCE, currency=EUR))
and lets you access the UserData by calling environment.getQa(); or environment.getStage();.
Another possible solution utilizes the TypeReference that can be provided for objectMapper.readValue() method. Here we parse the JSON into a Map<String, UserData>, skipping the Environment class, which makes it more dynamic, allowing you to add new environments just through the JSON:
String json = "{\n" + "\"QA\":{\n" + " \"customerName\":\"Customer QA\",\n"
+ " \"customerAddr\":\"UK\",\n" + " \"currency\": \"GBP\"\n" + " },\n"
+ "\"STAGE\" : {\n" + " \"customerName\":\"Customer STAGE\",\n"
+ " \"customerAddr\":\"FRANCE\",\n" + " \"currency\": \"EUR\"\n" + "}\n"
+ "}";
TypeReference<Map<String, UserData>> type = new TypeReference<Map<String, UserData>>() {
};
ObjectMapper objectMapper = new ObjectMapper();
Map<String, UserData> readValue = objectMapper.readValue(json, type);
System.out.println(readValue.get("STAGE"));
This prints:
UserData(customerName=Customer STAGE, customerAddr=FRANCE, currency=EUR)

Better way of writing validation for a JSON String

I have a JSON String:
{
"productName": "Gold",
"offerStartDate": "01152023",
"offerEndDate": "01152024",
"offerAttributes": [
{
"id": "TGH-DAD3KVF3",
"storeid": "STG-67925",
"availability": true
}
],
"offerSpecifications": {
"price": 23.25
}
}
The validation logic for the same is written as
Map<String, Object> map = mapper.readValue(json, Map.class);
String productNameValue = (String)map.get("productName");
if(productNameValue ==null && productNameValue.isEmpty()) {
throw new Exception();
}
String offerStartDateValue = (String)map.get("offerStartDate");
if(offerStartDateValue ==null && offerStartDateValue.isEmpty()) {
throw new Exception();
}
List<Object> offerAttributesValue = (List)map.get("offerAttributes");
if(offerAttributesValue ==null && offerAttributesValue.isEmpty()) {
throw new Exception();
}
Map<String, Object> offerSpecificationsValue = (Map)map.get("offerSpecifications");
if(offerSpecificationsValue ==null && offerSpecificationsValue.isEmpty() && ((String)offerSpecificationsValue.get("price")).isEmpty()) {
throw new Exception();
}
This is a portion of the JSON response. The actual response has more than 48 fields and the. The existing code has validation implemented for all the 48 fields as above. Note the responses are way complex than these.
I feel the validation code has very verbose and is very repetitive. How do, I fix this? What design pattern should I use to write a validation logic. I have seen builder pattern, but not sure how to use it for this scenario.
Build a JSON template for comparison.
ObjectMapper mapper = new ObjectMapper();
JsonNode template = mapper.readTree(
"{" +
" \"productName\": \"\"," +
" \"offerStartDate\": \"\"," +
" \"offerEndDate\": \"\"," +
" \"offerAttributes\": []," +
" \"offerSpecifications\": {" +
" \"price\": 0" +
" }" +
"}");
JsonNode data = mapper.readTree(
"{" +
" \"productName\": \"Gold\"," +
" \"offerStartDate\": \"01152023\"," +
" \"offerEndDate\": \"01152024\"," +
" \"offerAttributes\": [" +
" {" +
" \"id\": \"TGH-DAD3KVF3\"," +
" \"storeid\": \"STG-67925\"," +
" \"availability\": true" +
" }" +
" ]," +
" \"offerSpecifications\": {" +
" \"price\": 23.25" +
" }" +
"}");
validate(template, data);
Here is the recursion function to compare the template and the data.
public void validate(JsonNode template, JsonNode data) throws Exception {
final Iterator<Map.Entry<String, JsonNode>> iterator = template.fields();
while (iterator.hasNext()) {
final Map.Entry<String, JsonNode> entry = iterator.next();
JsonNode dataValue = data.get(entry.getKey());
if (dataValue == null || dataValue.isNull()) {
throw new Exception("Missing " + entry.getKey());
}
if (entry.getValue().getNodeType() != dataValue.getNodeType()) {
throw new Exception("Mismatch data type: " + entry.getKey());
}
switch (entry.getValue().getNodeType()) {
case STRING:
if (dataValue.asText().isEmpty()) {
throw new Exception("Missing " + entry.getKey());
}
break;
case OBJECT:
validate(entry.getValue(), dataValue);
break;
case ARRAY:
if (dataValue.isEmpty()) {
throw new Exception("Array " + entry.getKey() + " must not be empty");
}
break;
}
}
}
Option 1
If you are able to deserialize into a class instead of a map, you can use Bean Validaion to do something like this:
class Product {
#NotEmpty String productName;
#NotEmpty String offerStartDate;
#NotEmpty String offerEndDate;
}
You can then write your own #MyCustomValidation for any custom validation.
Option 2
If you must keep the object as a Map, you can extract each of your validations into validator objects make things extensible/composable/cleaner, roughly like this:
#FunctionalInterface
interface Constraint {
void validate(Object value);
default Constraint and(Constraint next) {
return (value) -> {
this.validate(value);
next.validate(value);
};
}
}
var constraints = new HashMap<Validator>();
constraints.put("productName", new NotEmpty());
constraints.put("offerStartDate", new NotEmpty());
constraints.put("someNumber", new LessThan(10).and(new GreaterThan(5)));
// Then
map.forEach((key, value) -> {
var constraint = constraints.get(key);
if (constraint != null) {
constraint.validate(value);
}
});
Hello, you can validate JSON with the following approach.
I created a mini, scaled-down version of yours but it should point you towards the right direction hopefully.
I used the Jackson libary, specifically I used the object mapper.
Here is some documentation to the object mapper - https://www.baeldung.com/jackson-object-mapper-tutorial.
So I created a simple Product class.
The Product class was composed of :
A empty constructor
An all arguments constructor
Three private properties, Name, Price, InStock
Getters & Setters
Here is my Main.java code.
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;
public class Main {
public static void main(String[] args) throws Exception {
// Mock JSON
String json = """
{
"name" : "",
"price" : 5.99,
"inStock": true
}""";
// Declare & Initialise a new object mapper
ObjectMapper mapper = new ObjectMapper();
// Declare & Initialise a new product object
Product product = null;
try {
// Try reading the values from the json into product object
product = mapper.readValue(json, Product.class);
}
catch (Exception exception) {
System.out.println("Exception");
System.out.println(exception.getMessage());
return;
}
// Map out the object's field names to the field values
Map<String, Object> propertiesOfProductObject = mapper.convertValue(product, Map.class);
// Loop through all the entries in the map. i.e. the fields and their values
for(Map.Entry<String, Object> entry : propertiesOfProductObject.entrySet()){
// If a value is empty throw an exception
// Else print it to the console
if (entry.getValue().toString().isEmpty()) {
throw new Exception("Missing Attribute : " + entry.getKey());
} else {
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
}
}
It throws an error sauing the name field is empty.

How to find the tag Value in the dynamic JSON-Object with Java 8

I have JSON-object which has a dynamic key inside it. I need to get a specific value mapped to this dynamic Key.
For example: value "10.00" will be returned for the key "value" and value REFUND_COMPLETED will be obtained as a result for the key "refundState"
Code:
public static void main(String[] args) {
String json2 = "{\n"
+ " \"refundStatusDetails\": {\n"
+ " \"txn_f2a7802c-ef84-43c3-8615-5f706b995c23\": {\n"
+ " \"refundTransactionId\": \"txn_f2a7802c-ef84-43c3-8615-5f706b995c23\",\n"
+ " \"requestId\": \"refund-request-id-1\",\n"
+ " \"refundState\": \"REFUND_COMPLETED\",\n"
+ " \"amount\": {\n"
+ " \"currency\": \"INR\",\n"
+ " \"value\": \"10.00\"\n"
+ " },\n"
+ " \"refundRequestedTime\": 1513788119505,\n"
+ "}";
System.out.println("JSON: " + json2);
JsonParser p = new JsonParser();
Map<String,String> res =check("refundState", p.parse(json2));
System.out.println("JSON: " + res.get("refundState"));
}
private static Map<String,String> check(String key, JsonElement jsonElement) {
Map<String,String> res = new HashMap<>();
if (jsonElement.isJsonObject()) {
Set<Map.Entry<String, JsonElement>> entrySet = jsonElement.getAsJsonObject().entrySet();
entrySet.stream().forEach((x) ->{
if (x.getKey().equals(key)) {
res.put(x.getKey(),x.getValue().toString());
}
});
}
return res;
}
If you are interested to access any field in a JSON object structure then you can use a method like the following one that I used to access the fields that I needed from an JSON Array structure using "package org.json;"
public static final String COLLECTION_OBJECT = "collectionObject";
public static final String FIELD = "field";
private ArrayList<Object> getSearchFilterCriteriaAsString() {
String jsonString = "{" +
"\n\"collectionObject\": " +
"[\n" +
"{" +
"\n\"field\": \"productId\"," +
"\n\"value\": \"3\"," +
"\n\"operator\": \"EQUALS\"\n" +
"},\n" +
"{" +
"\n\"field\": \"productPrice\"," +
"\n\"value\": \"15\"," +
"\n\"operator\": \"MORE_THAN\"\n" +
"},\n" +
"{" +
"\n\"field\": \"productQuantity\"," +
"\n\"value\": \"25\"," +
"\n\"operator\": \"LESS_THAN\"\n" +
"}\n" +
"]\n" +
"}";
JSONObject jsonObject = new JSONObject(jsonString);
JSONArray jsonArray = jsonObject.getJSONArray(COLLECTION_OBJECT);
ArrayList<Object> filteredObjectsList = new ArrayList<>();
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject filteredObj = (JSONObject) jsonArray.get(i);
filteredObjectsList.add(filteredObj.getString(FIELD));
}
}
return filteredObjectsList;
}
As long as you know your key values you can parse any JSON as deep you want, without to care about how big it is, how many attributes it has.
I have JSON Object which has a dynamic key inside the object I need a
specific key value
The recursive method listed below is capable of fetching the value mapped to the provided key from a nested JSON-object.
The method return an optional result.
If provided JsonElement is not a JsonObject an empty optional will be returned.
Otherwise, if the given JSON-object contains the given key the corresponding value wrapped by an optional will be returned. Or if it's not the case the entry set obtained from an object will be processed with stream. And for every JSON-object in the stream method getValue() will be called recursively.
If the given key is present in one of the nested objects, the first encountered non-empty optional will be returned. Or empty optional if the key was not found.
private static Optional<JsonElement> getValue(String key, JsonElement jsonElement) {
if (!jsonElement.isJsonObject()) {
return Optional.empty();
}
JsonObject source = jsonElement.getAsJsonObject();
return source.has(key) ? Optional.of(source.get(key)) :
source.entrySet().stream()
.map(Map.Entry::getValue)
.filter(JsonElement::isJsonObject)
.map(element -> getValue(key, element))
.filter(Optional::isPresent)
.findFirst()
.orElse(Optional.empty());
}
main() - demo
public static void main(String[] args) {
String json2 =
"""
{
"refundStatusDetails": {
"txn_f2a7802c-ef84-43c3-8615-5f706b995c23": {
"refundTransactionId": "txn_f2a7802c-ef84-43c3-8615-5f706b995c23",
"requestId": "refund-request-id-1",
"refundState": "REFUND_COMPLETED",
"amount": {
"currency": "INR",
"value": "10.00"
},
"refundRequestedTime": "1513788119505"
}
}
}""";
JsonElement element = JsonParser.parseString(json2);
System.out.println(getValue("refundState", element));
System.out.println(getValue("value", element));
}
Output
Optional["REFUND_COMPLETED"]
Optional["10.00"]
Note:
If you are using Java 17 you can utilize text blocks by plasing the text between the triple quotation marks """ JSON """.
Constructor of the JsonParser is deprecated. Instead of instantiating this class, we have to use its static methods.

Copy all values List<String> to Jackson JsonGenerator Array directly instead of looping over it

I am creating a JSON file using the Jackson JsonGenerator for which I need to add the elements from List<String>. This List consists of the JSON Fragments which needs to be added to my final JSON file.
As of now, I am looping over the List<String> and adding them to my Jackson JsonGenerator writeRaw one-by-one. This is working fine as of now. However, my List can have 1000s or more values then I do not wish to loop and add one by one. Rather than that, I am finding a way to directly add the array to the JsonGeneator array. I wanted to know if there is a way to directly copy the array something like this:
jsonGenerator.writeArray("eventList",eventsList);
Following is the code I have currently:
public class JacksonTest {
public static void main(String[] args) throws IOException {
List<String> eventsList = new ArrayList<>();
eventsList.add("{\n" + " \"isA\": \"Customer\",\n" + " \"name\": \"Rise Against\",\n" + " \"age\": \"2000\"\n" + "}");
eventsList.add("{\n" + " \"isA\": \"Owener\",\n" + " \"name\": \"Linkin Park\",\n" + " \"age\": \"2ßß8\"\n" + "}");
eventsList.add("{\n" + " \"isA\": \"Customer\",\n" + " \"name\": \"Breaking Benjamin\",\n" + " \"age\": \"2005\"\n" + "}");
StringWriter jsonObjectWriter = new StringWriter();
JsonGenerator jsonGenerator = new JsonFactory().createGenerator(jsonObjectWriter).useDefaultPrettyPrinter();
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("schema","2.0");
jsonGenerator.writeStringField("date","2021-06-22");
//Current Approach
jsonGenerator.writeFieldName("eventList");
jsonGenerator.writeStartArray();
//Add events from the list one by one
eventsList.forEach(event -> {
try {
jsonGenerator.writeRaw(event + ",");
} catch (IOException e) {
e.printStackTrace();
}
});
jsonGenerator.writeEndArray();
jsonGenerator.writeEndObject();
jsonGenerator.close();
jsonGenerator.flush();
System.out.println(jsonObjectWriter.toString());
}
}
As you can observe from the above code, I am looping over the List<String> and adding them to JsonGeneator one-by-one. Can someone please suggest if there is a way to directly add the List<String> to JsonGenerator so that I can skip the looping part.
Something similar is available in JSONObject here we can directly add the list:
final JSONObject doc = new JSONObject();
doc.put("schemaVersion", 2.0);
final JSONObject eventListAsJson = new JSONObject();
eventListAsJson.put("eventList", eventsList);
doc.put("eventList", eventListAsJson);
Any help or suggestion would be really appreciated.
As indicated by #Thomas I did the following to add the elements from LIST to my JsonGenerator:
jsonGenerator.writeRaw(String.join(",", eventsList));
ObjectNode objectNode = new ObjectMapper().createObjectNode();
objectNode.put("schema", "2.0");
objectNode.put("date", "2021-06-22");
ArrayNode arrayNode = new ObjectMapper().createArrayNode();
for (String s : eventsList) {
arrayNode.add(new ObjectMapper().readValue(s, ObjectNode.class));
}
objectNode.set("eventList", arrayNode);
System.out.println(objectNode.toPrettyString());

avoid nested if in hashmap which is created from complex json

I have a hashmap which has key value pair of String and object. It is the conversion of something like below json.
{
"test1": {
"test2": {
"test3": {
"key": "value"
},
"somefields12": "some value2"
},
"somefields": "some value"
}
}
But, I am not converting to map. I have just that map. If this may has key and value , I have to do write some logic based on that value. I implemented as below:
if (map.containsKey("test1") ) {
final HashMap<String, Object> test1 = (HashMap<String, Object>) map.get("test1");
if (test1.containsKey("test2")) {
final List<Object> test2 = (List<Object>) test1.get("test2");
if (!test2.isEmpty()) {
final HashMap<String, Object> test3 = (HashMap<String, Object>) test2.get(0);
if (test3.containsKey("key")) {
final String value = String.valueOf(test2.get("key"));
if (!StringUtils.isBlank(value)) {
//do some work based on value
}
}
}
}
}
Now, I wanted to avoid the nested if (multiple ifs) from my code. What would be the best way to do so?
I'm not familiar with the fancy new Java 8 features, so I'd do it the old fashioned way with a function that takes a path to look up, and walks the list with a loop:
import java.util.*;
class Test {
static String getByPath(HashMap<String, Object> map, String... path) {
for(int i=0; i<path.length-1; i++) {
map = (HashMap<String, Object>) map.get(path[i]);
if (map == null) return null;
}
Object value = map.get(path[path.length-1]);
return value == null ? null : String.valueOf(value);
}
public static void main(String[] args) {
HashMap<String, Object> map = new HashMap<>();
HashMap<String, Object> tmp1 = new HashMap<>();
HashMap<String, Object> tmp2 = new HashMap<>();
map.put("test1", tmp1);
tmp1.put("test2", tmp2);
tmp2.put("key1", "My Value");
System.out.println("With valid path: " + getByPath(map, "test1", "test2", "key1"));
System.out.println("With invalid path: " + getByPath(map, "test1", "BANANA", "key1"));
}
}
This results in:
With valid path: My Value
With invalid path: null
This can optionally be extended to:
Check that nodes are in fact maps before casting
Use Optional or a helpful exception instead of returning null
Using Gson library combined with java 8 Optional you can do something like this:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.util.Optional;
public class FindJsonKey {
public static final String JSON = "{\n" +
" \"test1\": {\n" +
" \"test2\": {\n" +
" \"test3\": {\n" +
" \"key\": \"value\"\n" +
" },\n" +
" \"somefields12\": \"some value2\"\n" +
" },\n" +
" \"somefields\": \"some value\"\n" +
" }\n" +
"}";
public static void main(String[] args) {
Gson gson = new GsonBuilder().create();
JsonObject jsonObject = gson.fromJson(JSON, JsonObject.class);
Optional
.ofNullable(jsonObject.getAsJsonObject("test1"))
.map(test1 -> test1.getAsJsonObject("test2"))
.map(test2 -> test2.getAsJsonObject("test3"))
.map(test3 -> test3.get("key"))
.map(JsonElement::getAsString)
.ifPresent(key -> {
// Do something with key..
});
}
}
A recursive solution that assumes the JSON structure is as given -- and ignores the names of the nested parent maps -- could look like the following:
/**
* Traverses the map from {#code nextEntry} until a key matching {#code keyTofind} is found
* or the bottom of the map is reached.
* The method assumes that any nested maps are contained in the first
* element of the parent map.
*
* #param nextEntry the next entry to search from
* #param keyToFind the stopping condition for the recursion
* #return the value matching {#code keyToFind} (may be empty)
*/
private static Optional<Object> find(Map.Entry<String,Object> nextEntry, String keyToFind) {
Object value = nextEntry.getValue();
if (nextEntry.getKey().equals(keyToFind)) {
return Optional.of(value);
} else if (nextEntry.getValue() instanceof Map) {
return find(((Map<String, Object>)nextEntry.getValue())
.entrySet().iterator().next(), keyToFind);
} else {
return Optional.empty();
}
}
Testing with the provided data (with help of Jackson for JSON parsing)
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Test {
private static final String JSON = "{ "
+ "\"test1\": {"
+ " \"test2\": {"
+ " \"test3\": {"
+ " \"key\": \"value\""
+ "},"
+ " \"somefields12\": \"some value2\""
+ "},"
+ " \"somefields\": \"some value\""
+ "}"
+ "}";
//...
public static void main(String[] args) throws Exception {
Map<String, Object> json = new ObjectMapper()
.readValue(JSON, new TypeReference<Map<String, Object>>() { });
final String keyToFind = "key";
Optional<Object> value = find(json.entrySet().iterator().next(), keyToFind);
System.out.println(value.isPresent() ? value.get() : "null");
}
}
gives
value

Categories