{
"firstName": "John",
"lastName": "doe",
"age": 26,
"address": {
"streetAddress": "naist street",
"city": "Nara",
"postalCode": "630-0192"
},
"phoneNumbers": [
{
"type": "iPhone",
"number": "0123-4567-8888"
},
{
"type": "home",
"number": "0123-4567-8910"
}
]
}
mockMvc.perform(get("/user/John"))
.andExpect(jsonPath("$.phoneNumbers[*].type").value( ??? ));
I was trying to make an assertion like something above, but there is no proper matcher helpers currently for the default JsonProvider
(JsonSmartJsonProvider
).
I opened https://github.com/netplex/json-smart-v2/issues/162 to asking for JsonSmartMatchers
as I cannot change what JsonProvider
jsonPath() uses now.
This prevents me from choosing other JsonProvider
who might have matcher helpers already.
Comment From: DevDengChao
I suggest add a jsonPathResultMatchers.using(Class<T extends JsonProvider> provider)
to allow us choosing another JsonProvider
.
Comment From: DevDengChao
Related issue: https://github.com/json-path/JsonPath/issues/918
Comment From: DevDengChao
I found https://github.com/lukas-krecan/JsonUnit might helps me.
Comment From: sbrannen
Hi @DevDengChao,
I was trying to make an assertion like something above, but there is no proper matcher helpers currently for the default
JsonProvider
(JsonSmartJsonProvider
).
Are you saying the default JsonProvider
fails to parse your JSON content?
Or are you saying that Spring's JsonPathResultMatchers
does not provide a method that would support your use case?
Or are you saying something else? If so, please expound.
Thanks
Comment From: DevDengChao
are you saying that Spring's JsonPathResultMatchers does not provide a method that would support your use case?
Yes, there is no helper methods I can use to assert something is a json array which contains certain elements.
Comment From: DevDengChao
Even one of the JsonProvider implementation has such api, I can not switch between implementations jsonPath() uses now.
Comment From: sbrannen
are you saying that Spring's JsonPathResultMatchers does not provide a method that would support your use case?
Yes, there is no helper methods I can use to assert something is a json array which contains certain elements.
You are free to use any core Hamcrest matcher as well as any matchers from third-party libraries or matchers that you create yourself.
For the specific use case you've outlined, the following test class demonstrates that it's possible with built-in matchers from Hamcrest.
import org.junit.jupiter.api.Test;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.hamcrest.CoreMatchers.either;
import static org.hamcrest.CoreMatchers.everyItem;
import static org.hamcrest.CoreMatchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
class JsonPathArrayTests {
private MockMvc mockMvc= standaloneSetup(new PersonController())
.defaultRequest(get("/").accept(MediaType.APPLICATION_JSON))
.alwaysExpect(status().isOk())
.alwaysExpect(content().contentType("application/json"))
.build();
@Test
void getPerson() throws Exception {
String phoneNumberTypes = "$.phoneNumbers[*].type";
mockMvc.perform(get("/person"))
.andExpect(jsonPath(phoneNumberTypes).isArray())
.andExpect(jsonPath(phoneNumberTypes).value(everyItem(either(is("iPhone")).or(is("home")))));
}
@RestController
private static class PersonController {
@RequestMapping("/person")
String get() {
return """
{
"firstName": "John",
"lastName": "doe",
"age": 26,
"address": {
"streetAddress": "naist street",
"city": "Nara",
"postalCode": "630-0192"
},
"phoneNumbers": [
{
"type": "iPhone",
"number": "0123-4567-8888"
},
{
"type": "home",
"number": "0123-4567-8910"
}
]
}
""";
}
}
}
Comment From: sbrannen
Even one of the JsonProvider implementation has such api, I can not switch between implementations jsonPath() uses now.
I agree that it could be useful to provide a custom (or non-default) JsonProvider
if you are facing issues with parsing, but I don't see how changing the default JsonProvider
would benefit your use case.
Comment From: DevDengChao
@sbrannen Thanks for your code snippet, I should dig Hamcrest more before opening this issue.
I don't see how changing the default JsonProvider would benefit your use case.
As I metioned in https://github.com/netplex/json-smart-v2/issues/162#issuecomment-1760669510, something like https://github.com/Crunc/hamcrest-json-matchers provides some helper methods which could make assertions on json array, but it dosen't compatible with JsonSmart json array, if I could switch to other JsonProvider implementations, then I can choose to use such libs instead of write a long chain of Hamcrest matchers myself.
Comment From: rstoyanchev
I've created #31651 to open up JsonPathExpectationsHelper
so you can follow that instead.