So I'm working on the below json:
{
"id": "",
"owner": "some dude",
"metaData": {
"request": {
"ref": null,
"contacts":[
{
"email": null,
"name": null,
"contactType": "R"
},
{
"email": null,
"name": "Dante",
"contactType": "S"
}
]
}
}
}
I want to retrieve the name
of contact has type S
and only the first one that returned.
Using jsonpath with this path "$..contacts[?(@.contactType == 'S')].name"
always return an array of string because a filter operation always return result as an array.
So I tried "$..contacts[?(@.contactType == 'S')].name[0]"
and "$..contacts[?(@.contactType == 'S')][0].name"
but no luck. Those path returns empty results.
So my question is, is there any way to get only first element when using filter in jsonpath. I'm currently using jayway jsonpath v2.2.0.
If you use jsonpath with MockMvc class from spring-test, then you may write the following dummy matcher:
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.core.IsEqual;
import net.minidev.json.JSONArray;
public class FirstMatcher<T> extends BaseMatcher<T> {
private final Matcher<?> matcher;
public static <T> FirstMatcher<T> matcher(Matcher<T> matcher) {
return new FirstMatcher<T>(matcher);
}
public static FirstMatcher<Object> value(Object value) {
return new FirstMatcher<Object>(value);
}
public FirstMatcher(Matcher<T> matcher) {
this.matcher = matcher;
}
public FirstMatcher(Object value) {
this.matcher = new IsEqual<Object>(value);
}
@Override
public void describeTo(Description description) {
description.appendText("first matcher");
}
@Override
public boolean matches(Object item) {
if (!(item instanceof JSONArray)) {
return false;
}
JSONArray array = (JSONArray)item;
if (array.isEmpty()) {
return false;
}
Object obj = array.get(0);
return matcher.matches(obj);
}
}
And use the following way:
mockMvc.
perform(get(url).
accept(MediaType.APPLICATION_JSON).accept(MediaType.TEXT_PLAIN).accept(MediaType.ALL)).
andExpect(status().isOk()).
andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)).
andExpect(jsonPath("$.properties[?(@.propertyName == 'name1')].description").value(FirstMatcher.matcher(IsNull.nullValue()))).
andExpect(jsonPath("$.properties[?(@.propertyName == 'name2')].required").value(FirstMatcher.value(true)));
P.S. Since net.minidev.json.JSONArray subclasses java.util.List, one may cast to List or even Iterable rather than to net.minidev.json.JSONArray. :)
The quickest solution I found was just comparing it with a list, so like this in your scenario:
.andExpect(jsonPath("$..contacts[?(@.contactType == 'S')].name", equalTo(Arrays.asList("Dante"))))
(Assuming you are trying to compare some result in a test of course)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With