Please add a method for JSONCompareMode.NON_EXTENSIBLE to JsonExpectationsHelper in spring-test.

Because: mostly you want to assert that both requests contain exactly the same content and the same fields. But order of elements usually does not matter, as json is nothing other than a HashMap.

That's simply not possible to assert as of now.

NON_EXTENSIBLE is the correct mode in that case.

Comment From: sbrannen

JsonExpectationsHelper is primarily intended for use within the framework itself, and it is essentially just a wrapper around org.skyscreamer.jsonassert.JSONAssert.

If you have been using JsonExpectationsHelper directly in your code and want to make use of JSONCompareMode, we would recommend that you instead use JSONAssert.

Or... are you hoping to see more lenient matching in classes such as org.springframework.test.web.client.match.ContentRequestMatchers, org.springframework.test.web.servlet.result.ContentResultMatchers, and org.springframework.test.web.reactive.server.WebTestClient?

Comment From: membersound

Ok indeed that would make sense to directly use JSONAssert. Still, if there is room for improved lenient json matching directly in the ContentMatchers, that would also be nice.

Comment From: sbrannen

Actually, we already have support for choosing between lenient and strict matching:

  • org.springframework.test.web.client.match.ContentRequestMatchers.json(String, boolean)
  • org.springframework.test.web.servlet.result.ContentResultMatchers.json(String, boolean)

If you supply true for the above strict flags, JSONCompareMode.STRICT is used, but if you supply false that switches to JSONCompareMode.LENIENT.

Those delegate to JsonExpectationsHelper.assertJsonEqual(String, String, boolean) which in turn delegates to org.skyscreamer.jsonassert.JSONAssert.assertEquals(String, String, boolean).

Please note as well that JsonExpectationsHelper.assertJsonEqual(String, String) applies lenient matching by default, and that is used by DefaultWebTestClient.DefaultBodyContentSpec.json(String).

In light of that, I'm going to close this issue.

Comment From: membersound

If you supply true for the above strict flags, JSONCompareMode.STRICT is used, but if you supply false that switches to JSONCompareMode.LENIENT.

Well but that's exactly the problem: LENIENT will not detect of one of the comparable values contains additional elements. You mostly don't want that. STRICT fixes this, but requires strict order of elements. Which for a json hashmap is kind of useless, as json is per definition unsorted.

Thus, one should mostly use the NON_EXTENSIBLE mode (which does not allow additional elements, but allows different order). And this mode is afaik not possible with ContentRequestMatchers or ContentResultMatchers.

Wouldn't it be worth extending the testclasses so that either JSONCompareMode can be supplied as parameter, or add a NON_EXTENSIBLE matcher method explicit?

To add some insight on a real world case: yesterday I discovered that some of my JUnit tests should have failed because in one of the json items, there was introduced a new field. But they did not, as by default the lenient mode explicit allows this behavior. And mostly this will be unintended, also for other users. I assume.

Comment From: sbrannen

Thus, one should mostly use the NON_EXTENSIBLE mode (which does not allow additional elements, but allows different order). And this mode is afaik not possible with ContentRequestMatchers or ContentResultMatchers.

That's correct.

Wouldn't it be worth extending the test classes so that either JSONCompareMode can be supplied as parameter,

We likely wouldn't want to introduce JSONCompareMode as a parameter in order to avoid a direct dependency on JSONAssert in the API. JSONAssert is of course used under the hood as an implementation detail, but exposing that in the top-level APIs would prevent us from switching to a different implementation at a later date if desired.

or add a NON_EXTENSIBLE matcher method explicit?

That would be an option, though we'd likely have to introduce a method with a name other than json(...) since we cannot introduce another json(String, boolean) variant.

@rstoyanchev and @sdeleuze, thoughts?

Comment From: membersound

What about adding your own spring enum type that resembles to JSONCompareMode? You're then free of api changes in future with json(String, SpringJsonCompareMode), but give the user the ability to directly chose the desired mode.

Some of them can then delegate to existing json(String, true) and json(String, false), while another delegates explicit to the NON_EXTENSIBLE?

Comment From: AviranBac

What about adding your own spring enum type that resembles to JSONCompareMode? You're then free of api changes in future with json(String, SpringJsonCompareMode), but give the user the ability to directly chose the desired mode.

Some of them can then delegate to existing json(String, true) and json(String, false), while another delegates explicit to the NON_EXTENSIBLE?

Hey, I strongly suggest this idea since I also found myself looking for a NON_EXTENSIBLE solution in your API but there isn't an implementation for it at the moment. I hope you can reconsider and reopen this issue.

Comment From: miriSch

@sbrannen is there a chance that the issue will be reopened? I could also use this.