11package org .mockserver .matchers ;
22
33import com .fasterxml .jackson .annotation .JsonIgnore ;
4+ import com .fasterxml .jackson .core .JsonProcessingException ;
5+ import com .fasterxml .jackson .databind .JsonNode ;
6+ import com .fasterxml .jackson .databind .ObjectWriter ;
7+ import com .google .common .base .Joiner ;
8+ import net .javacrumbs .jsonunit .core .Configuration ;
9+ import net .javacrumbs .jsonunit .core .internal .Diff ;
10+ import net .javacrumbs .jsonunit .core .internal .Options ;
11+ import net .javacrumbs .jsonunit .core .listener .Difference ;
12+ import net .javacrumbs .jsonunit .core .listener .DifferenceContext ;
13+ import net .javacrumbs .jsonunit .core .listener .DifferenceListener ;
414import org .mockserver .log .model .LogEntry ;
515import org .mockserver .logging .MockServerLogger ;
616import org .mockserver .model .HttpRequest ;
7- import org .skyscreamer .jsonassert .JSONCompareMode ;
8- import org .skyscreamer .jsonassert .JSONCompareResult ;
17+ import org .mockserver .serialization .ObjectMapperFactory ;
918
19+ import java .util .ArrayList ;
20+ import java .util .List ;
21+
22+ import static net .javacrumbs .jsonunit .core .Option .*;
1023import static org .apache .commons .lang3 .StringUtils .isBlank ;
11- import static org .skyscreamer .jsonassert .JSONCompare .compareJSON ;
1224import static org .slf4j .event .Level .DEBUG ;
1325
1426/**
1527 * @author jamesdbloom
1628 */
1729public class JsonStringMatcher extends BodyMatcher <String > {
1830 private static final String [] EXCLUDED_FIELDS = {"mockServerLogger" };
31+ private static final ObjectWriter PRETTY_PRINTER = ObjectMapperFactory .createObjectMapper ().writerWithDefaultPrettyPrinter ();
1932 private final MockServerLogger mockServerLogger ;
2033 private final String matcher ;
34+ private JsonNode matcherJsonNode ;
2135 private final MatchType matchType ;
2236
2337 JsonStringMatcher (MockServerLogger mockServerLogger , String matcher , MatchType matchType ) {
2438 this .mockServerLogger = mockServerLogger ;
2539 this .matcher = matcher ;
40+
2641 this .matchType = matchType ;
2742 }
2843
2944 public boolean matches (final HttpRequest context , String matched ) {
3045 boolean result = false ;
3146
32- JSONCompareResult jsonCompareResult ;
3347 try {
3448 if (isBlank (matcher )) {
3549 result = true ;
3650 } else {
37- JSONCompareMode jsonCompareMode = JSONCompareMode .LENIENT ;
38- if (matchType == MatchType .STRICT ) {
39- jsonCompareMode = JSONCompareMode .STRICT ;
51+ Options options = Options .empty ();
52+ switch (matchType ) {
53+ case STRICT :
54+ break ;
55+ case ONLY_MATCHING_FIELDS :
56+ options = options .with (
57+ IGNORING_ARRAY_ORDER ,
58+ IGNORING_EXTRA_ARRAY_ITEMS ,
59+ IGNORING_EXTRA_FIELDS
60+ );
61+ break ;
4062 }
41- jsonCompareResult = compareJSON (matcher , matched , jsonCompareMode );
63+ final DiffListener diffListener = new DiffListener ();
64+ Configuration diffConfig = Configuration .empty ().withDifferenceListener (diffListener ).withOptions (options );
4265
43- if (jsonCompareResult .passed ()) {
44- result = true ;
45- }
46-
47- if (!result ) {
66+ try {
67+ if (matcherJsonNode == null ) {
68+ matcherJsonNode = ObjectMapperFactory .createObjectMapper ().readTree (matcher );
69+ }
70+ result = Diff
71+ .create (
72+ matcherJsonNode ,
73+ ObjectMapperFactory .createObjectMapper ().readTree (matched ),
74+ "" ,
75+ "" ,
76+ diffConfig
77+ )
78+ .similar ();
79+ } catch (Throwable throwable ) {
4880 mockServerLogger .logEvent (
4981 new LogEntry ()
5082 .setLogLevel (DEBUG )
5183 .setHttpRequest (context )
52- .setMessageFormat ("failed to perform json match of{}with{}because{}" )
53- .setArguments (matched , this .matcher , jsonCompareResult .getMessage ())
84+ .setMessageFormat ("exception while perform json match of{}with{}" )
85+ .setArguments (matched , this .matcher )
86+ .setThrowable (throwable )
5487 );
5588 }
89+
90+ if (!result ) {
91+ if (diffListener .differences .isEmpty ()) {
92+ mockServerLogger .logEvent (
93+ new LogEntry ()
94+ .setLogLevel (DEBUG )
95+ .setHttpRequest (context )
96+ .setMessageFormat ("failed to perform json match of{}with{}" )
97+ .setArguments (matched , this .matcher )
98+ );
99+ } else {
100+ mockServerLogger .logEvent (
101+ new LogEntry ()
102+ .setLogLevel (DEBUG )
103+ .setHttpRequest (context )
104+ .setMessageFormat ("failed to perform json match of{}with{}because{}" )
105+ .setArguments (matched , this .matcher , Joiner .on (",\n " ).join (diffListener .differences ))
106+ );
107+ }
108+ }
56109 }
57110 } catch (Exception e ) {
58111 mockServerLogger .logEvent (
@@ -68,6 +121,34 @@ public boolean matches(final HttpRequest context, String matched) {
68121 return not != result ;
69122 }
70123
124+ private static class DiffListener implements DifferenceListener {
125+
126+ public List <String > differences = new ArrayList <>();
127+
128+ @ Override
129+ public void diff (Difference difference , DifferenceContext context ) {
130+ switch (difference .getType ()) {
131+ case EXTRA :
132+ differences .add ("additional element at \" " + difference .getActualPath () + "\" with value: " + prettyPrint (difference .getActual ()));
133+ break ;
134+ case MISSING :
135+ differences .add ("missing element at \" " + difference .getActualPath () + "\" " );
136+ break ;
137+ case DIFFERENT :
138+ differences .add ("wrong value at \" " + difference .getActualPath () + "\" , expected: " + prettyPrint (difference .getExpected ()) + " but was: " + prettyPrint (difference .getActual ()));
139+ break ;
140+ }
141+ }
142+
143+ private String prettyPrint (Object value ) {
144+ try {
145+ return PRETTY_PRINTER .writeValueAsString (value );
146+ } catch (JsonProcessingException e ) {
147+ return String .valueOf (value );
148+ }
149+ }
150+ }
151+
71152 @ Override
72153 @ JsonIgnore
73154 protected String [] fieldsExcludedFromEqualsAndHashCode () {
0 commit comments