Skip to content

Commit fcb8a3b

Browse files
committed
#731 #738 replaced JSONassert with JsonUnit to improve JSON matching and remove problematic transitive dependencies
1 parent 09e4b0f commit fcb8a3b

File tree

3 files changed

+101
-20
lines changed

3 files changed

+101
-20
lines changed

mockserver-core/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@
106106
</exclusions>
107107
</dependency>
108108
<dependency>
109-
<groupId>org.skyscreamer</groupId>
110-
<artifactId>jsonassert</artifactId>
109+
<groupId>net.javacrumbs.json-unit</groupId>
110+
<artifactId>json-unit-core</artifactId>
111111
</dependency>
112112

113113
<!-- json validation -->

mockserver-core/src/main/java/org/mockserver/matchers/JsonStringMatcher.java

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,111 @@
11
package org.mockserver.matchers;
22

33
import 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;
414
import org.mockserver.log.model.LogEntry;
515
import org.mockserver.logging.MockServerLogger;
616
import 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.*;
1023
import static org.apache.commons.lang3.StringUtils.isBlank;
11-
import static org.skyscreamer.jsonassert.JSONCompare.compareJSON;
1224
import static org.slf4j.event.Level.DEBUG;
1325

1426
/**
1527
* @author jamesdbloom
1628
*/
1729
public 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() {

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,9 @@
271271
<version>${jackson.version}</version>
272272
</dependency>
273273
<dependency>
274-
<groupId>org.skyscreamer</groupId>
275-
<artifactId>jsonassert</artifactId>
276-
<version>1.5.0</version>
274+
<groupId>net.javacrumbs.json-unit</groupId>
275+
<artifactId>json-unit-core</artifactId>
276+
<version>2.14.0</version>
277277
</dependency>
278278

279279
<!-- json validation -->

0 commit comments

Comments
 (0)