diff --git a/mockserver-core/pom.xml b/mockserver-core/pom.xml
index 9e1efe33f..a992187fa 100644
--- a/mockserver-core/pom.xml
+++ b/mockserver-core/pom.xml
@@ -106,8 +106,8 @@
- org.skyscreamer
- jsonassert
+ net.javacrumbs.json-unit
+ json-unit-core
diff --git a/mockserver-core/src/main/java/org/mockserver/matchers/JsonStringMatcher.java b/mockserver-core/src/main/java/org/mockserver/matchers/JsonStringMatcher.java
index 7bd05cf16..fea13a6ac 100644
--- a/mockserver-core/src/main/java/org/mockserver/matchers/JsonStringMatcher.java
+++ b/mockserver-core/src/main/java/org/mockserver/matchers/JsonStringMatcher.java
@@ -1,14 +1,26 @@
package org.mockserver.matchers;
import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectWriter;
+import com.google.common.base.Joiner;
+import net.javacrumbs.jsonunit.core.Configuration;
+import net.javacrumbs.jsonunit.core.internal.Diff;
+import net.javacrumbs.jsonunit.core.internal.Options;
+import net.javacrumbs.jsonunit.core.listener.Difference;
+import net.javacrumbs.jsonunit.core.listener.DifferenceContext;
+import net.javacrumbs.jsonunit.core.listener.DifferenceListener;
import org.mockserver.log.model.LogEntry;
import org.mockserver.logging.MockServerLogger;
import org.mockserver.model.HttpRequest;
-import org.skyscreamer.jsonassert.JSONCompareMode;
-import org.skyscreamer.jsonassert.JSONCompareResult;
+import org.mockserver.serialization.ObjectMapperFactory;
+import java.util.ArrayList;
+import java.util.List;
+
+import static net.javacrumbs.jsonunit.core.Option.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
-import static org.skyscreamer.jsonassert.JSONCompare.compareJSON;
import static org.slf4j.event.Level.DEBUG;
/**
@@ -16,43 +28,84 @@
*/
public class JsonStringMatcher extends BodyMatcher {
private static final String[] EXCLUDED_FIELDS = {"mockServerLogger"};
+ private static final ObjectWriter PRETTY_PRINTER = ObjectMapperFactory.createObjectMapper().writerWithDefaultPrettyPrinter();
private final MockServerLogger mockServerLogger;
private final String matcher;
+ private JsonNode matcherJsonNode;
private final MatchType matchType;
JsonStringMatcher(MockServerLogger mockServerLogger, String matcher, MatchType matchType) {
this.mockServerLogger = mockServerLogger;
this.matcher = matcher;
+
this.matchType = matchType;
}
public boolean matches(final HttpRequest context, String matched) {
boolean result = false;
- JSONCompareResult jsonCompareResult;
try {
if (isBlank(matcher)) {
result = true;
} else {
- JSONCompareMode jsonCompareMode = JSONCompareMode.LENIENT;
- if (matchType == MatchType.STRICT) {
- jsonCompareMode = JSONCompareMode.STRICT;
+ Options options = Options.empty();
+ switch (matchType) {
+ case STRICT:
+ break;
+ case ONLY_MATCHING_FIELDS:
+ options = options.with(
+ IGNORING_ARRAY_ORDER,
+ IGNORING_EXTRA_ARRAY_ITEMS,
+ IGNORING_EXTRA_FIELDS
+ );
+ break;
}
- jsonCompareResult = compareJSON(matcher, matched, jsonCompareMode);
+ final DiffListener diffListener = new DiffListener();
+ Configuration diffConfig = Configuration.empty().withDifferenceListener(diffListener).withOptions(options);
- if (jsonCompareResult.passed()) {
- result = true;
- }
-
- if (!result) {
+ try {
+ if (matcherJsonNode == null) {
+ matcherJsonNode = ObjectMapperFactory.createObjectMapper().readTree(matcher);
+ }
+ result = Diff
+ .create(
+ matcherJsonNode,
+ ObjectMapperFactory.createObjectMapper().readTree(matched),
+ "",
+ "",
+ diffConfig
+ )
+ .similar();
+ } catch (Throwable throwable) {
mockServerLogger.logEvent(
new LogEntry()
.setLogLevel(DEBUG)
.setHttpRequest(context)
- .setMessageFormat("failed to perform json match of{}with{}because{}")
- .setArguments(matched, this.matcher, jsonCompareResult.getMessage())
+ .setMessageFormat("exception while perform json match of{}with{}")
+ .setArguments(matched, this.matcher)
+ .setThrowable(throwable)
);
}
+
+ if (!result) {
+ if (diffListener.differences.isEmpty()) {
+ mockServerLogger.logEvent(
+ new LogEntry()
+ .setLogLevel(DEBUG)
+ .setHttpRequest(context)
+ .setMessageFormat("failed to perform json match of{}with{}")
+ .setArguments(matched, this.matcher)
+ );
+ } else {
+ mockServerLogger.logEvent(
+ new LogEntry()
+ .setLogLevel(DEBUG)
+ .setHttpRequest(context)
+ .setMessageFormat("failed to perform json match of{}with{}because{}")
+ .setArguments(matched, this.matcher, Joiner.on(",\n").join(diffListener.differences))
+ );
+ }
+ }
}
} catch (Exception e) {
mockServerLogger.logEvent(
@@ -68,6 +121,34 @@ public boolean matches(final HttpRequest context, String matched) {
return not != result;
}
+ private static class DiffListener implements DifferenceListener {
+
+ public List differences = new ArrayList<>();
+
+ @Override
+ public void diff(Difference difference, DifferenceContext context) {
+ switch (difference.getType()) {
+ case EXTRA:
+ differences.add("additional element at \"" + difference.getActualPath() + "\" with value: " + prettyPrint(difference.getActual()));
+ break;
+ case MISSING:
+ differences.add("missing element at \"" + difference.getActualPath() + "\"");
+ break;
+ case DIFFERENT:
+ differences.add("wrong value at \"" + difference.getActualPath() + "\", expected: " + prettyPrint(difference.getExpected()) + " but was: " + prettyPrint(difference.getActual()));
+ break;
+ }
+ }
+
+ private String prettyPrint(Object value) {
+ try {
+ return PRETTY_PRINTER.writeValueAsString(value);
+ } catch (JsonProcessingException e) {
+ return String.valueOf(value);
+ }
+ }
+ }
+
@Override
@JsonIgnore
protected String[] fieldsExcludedFromEqualsAndHashCode() {
diff --git a/pom.xml b/pom.xml
index 35bf98791..35fa4c04c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -271,9 +271,9 @@
${jackson.version}
- org.skyscreamer
- jsonassert
- 1.5.0
+ net.javacrumbs.json-unit
+ json-unit-core
+ 2.14.0