Given the following JSON:
{
"full_report": {
"score": "5",
"history": {
"record": [
{
"name": "John Smith",
"SSN": "123456789",
"last_visit": "02.03.2019",
"expiry_date": "15.03.2019"
},
{
"name": "John Doe",
"SSN": "987654321",
"last_visit": "05.03.2019",
"expiry_date": "15.09.2019"
},
{
"name": "Jane Doe",
"SSN": "999999999",
"last_visit": "02.03.2019"
}
]
}
}
}
I would like to be able to use JsonPath to find if any of the objects under the record array are missing the expiry_date
key and value pair. I currently have a working solution using a method that adds all entries of record
to one list and all entries of expiry_date
to another and simply checks if the subtraction of both list sizes equals 0 to return a boolean value.
public Boolean isMissing(String json, String expression) {
String[] expr = expression.split(";");
List<String> totalRecords = JsonPath.read(json, expr[0]);
List<String> foundRecords = JsonPath.read(json, expr[1]);
return totalRecords.size() - foundRecords.size() != 0;
}
This requires using two JsonPath expressions with a ;
delimiter like so which causes some other, unrelated issues that I'd like to avoid:
$.full_report.history.record[?(@.expiry_date)];$.full_report.history.record[*]
For a copy of this exact structure in XML I can use an XPath expression like so: boolean(full_report/history/record[not(expiry_date/text())])
Any chance there's an equivalent filter that I may have missed in JsonPath?
Update
The answer below by Saeed Alizadeh to use predicate does not solve the problem of having to pass in the property to look for in the first place.
It did help make the method and passing in the property a fair bit cleaner as there's no longer a need to write two separate expressions rather than expression;property_to_lookup
. As seen in the method below, that fundamental issue still remains but is much more hassle-free:
public Boolean isMissing(String json, String expression) {
String[] expressionAndPredicate = expression.split(";");
Predicate missingKeyValue = predicateContext -> {
Object missingKey = predicateContext.item(Map.class).get(expressionAndPredicate[1]);
return missingKey == null || missingKey.toString().length() <= 0;
};
List<String> records = JsonPath.read(json, expressionAndPredicate[0], missingKeyValue);
return records.size() != 0;
}
I don't want to add a 3rd parameter to the method for the property nor split the incoming string to sidestep the issue as it creates some issues when providing the JsonPath expression as input at the endpoint. If no one-line expression exists similar to the XPath example, I'll mark the question as answered by Saeed.
As you can see example below by using predicate you can filter result:
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Predicate;
import java.util.List;
import java.util.Map;
public class Main {
public static void main(String[] args) {
String json = "{\n" +
" \"full_report\": {\n" +
" \"score\": \"5\",\n" +
" \"history\": {\n" +
" \"record\": [\n" +
" {\n" +
" \"name\": \"John Smith\",\n" +
" \"SSN\": \"123456789\",\n" +
" \"last_visit\": \"02.03.2019\",\n" +
" \"expiry_date\": \"15.03.2019\"\n" +
" },\n" +
" {\n" +
" \"name\": \"John Doe\",\n" +
" \"SSN\": \"987654321\",\n" +
" \"last_visit\": \"05.03.2019\",\n" +
" \"expiry_date\": \"15.09.2019\"\n" +
" },\n" +
" {\n" +
" \"name\": \"Jane Doe\",\n" +
" \"SSN\": \"999999999\",\n" +
" \"last_visit\": \"02.03.2019\"\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
"}";
Predicate expiry_date = new Predicate() {
public boolean apply(PredicateContext predicateContext) {
Object expiry_date = predicateContext.item(Map.class).get("expiry_date");
return expiry_date != null && expiry_date.toString().length() > 0 ? false : true;
}
};
List records = JsonPath.parse(json).read("full_report.history.record[?]", List.class, expiry_date);
System.out.println(records);
}
}
this will print following output as the only record missing " expiry_date " property
[{"name":"Jane Doe","SSN":"999999999","last_visit":"02.03.2019"}]
update
public static boolean isMissing(String json, final String jsonProperty) {
Predicate predicate = new Predicate() {
public boolean apply(PredicateContext predicateContext) {
Object propertyObject = predicateContext.item(Map.class).get(jsonProperty);
return propertyObject != null && propertyObject.toString().length() > 0 ? false : true;
}
};
List records = JsonPath.parse(json).read("full_report.history.record[?]", List.class, predicate);
return (records != null && records.size() > 0) ? true : false;
}
output:
System.out.println(isMissing(json, "expiry_date")); // prints true
System.out.println(isMissing(json, "name")); // prints false
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.