{
    "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.