diff --git a/build.gradle b/build.gradle index 8ffa1a34..bae122d2 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { repositories { mavenCentral() maven { - url "http://repo.springsource.org/plugins-release"; + url "https://repo.springsource.org/plugins-release"; } } dependencies { diff --git a/src/main/java/com/github/fge/jsonpatch/diff/DiffOptions.java b/src/main/java/com/github/fge/jsonpatch/diff/DiffOptions.java new file mode 100644 index 00000000..ec040d73 --- /dev/null +++ b/src/main/java/com/github/fge/jsonpatch/diff/DiffOptions.java @@ -0,0 +1,40 @@ +package com.github.fge.jsonpatch.diff; + +/** + * Created by AMA on 24/09/2020. + */ +public class DiffOptions { + + public static final boolean DIFF_DOESNT_REQUIRE_SOURCE = false; + + final boolean diffDoesntRequireSource; + + public static final DiffOptions DEFAULT_OPTIONS = new DiffOptions(DIFF_DOESNT_REQUIRE_SOURCE); + + private DiffOptions(boolean diffDoesntRequireSource) { + this.diffDoesntRequireSource = diffDoesntRequireSource; + } + + public boolean isDiffDoesntRequireSource() { + return diffDoesntRequireSource; + } + + public static class Builder { + private boolean diffDoesntRequireSource = DIFF_DOESNT_REQUIRE_SOURCE; + + public Builder diffDoesntRequireSource() { + diffDoesntRequireSource = true; + return this; + } + + public Builder diffRequireSource() { + diffDoesntRequireSource = false; + return this; + } + + public DiffOptions build(){ + return new DiffOptions(diffDoesntRequireSource); + } + + } +} diff --git a/src/main/java/com/github/fge/jsonpatch/diff/DiffProcessor.java b/src/main/java/com/github/fge/jsonpatch/diff/DiffProcessor.java index 299d29a1..75ed074a 100644 --- a/src/main/java/com/github/fge/jsonpatch/diff/DiffProcessor.java +++ b/src/main/java/com/github/fge/jsonpatch/diff/DiffProcessor.java @@ -36,10 +36,18 @@ final class DiffProcessor private final Map unchanged; + private final DiffOptions options; + public static final boolean DIFF_DOESNT_REQUIRE_SOURCE = false; + private final List diffs = new ArrayList(); - DiffProcessor(final Map unchanged) + DiffProcessor(final Map unchanged) { + this(unchanged, DiffOptions.DEFAULT_OPTIONS); + } + + DiffProcessor(final Map unchanged, final DiffOptions options) { + this.options = options; this.unchanged = Collections.unmodifiableMap(new HashMap(unchanged)); } @@ -56,6 +64,10 @@ void valueRemoved(final JsonPointer pointer, final JsonNode value) void valueAdded(final JsonPointer pointer, final JsonNode value) { + if (options.isDiffDoesntRequireSource()) { + diffs.add(DiffOperation.add(pointer, value)); + return; + } final int removalIndex = findPreviouslyRemoved(value); if (removalIndex != -1) { final DiffOperation removed = diffs.get(removalIndex); diff --git a/src/main/java/com/github/fge/jsonpatch/diff/JsonDiff.java b/src/main/java/com/github/fge/jsonpatch/diff/JsonDiff.java index 302a79c2..dccf9d71 100644 --- a/src/main/java/com/github/fge/jsonpatch/diff/JsonDiff.java +++ b/src/main/java/com/github/fge/jsonpatch/diff/JsonDiff.java @@ -36,6 +36,8 @@ import java.io.IOException; import java.util.*; +import static com.github.fge.jsonpatch.diff.DiffProcessor.DIFF_DOESNT_REQUIRE_SOURCE; + /** * JSON "diff" implementation * @@ -81,14 +83,25 @@ private JsonDiff() * * @since 1.9 */ + +// public static JsonPatch asJsonPatch(final JsonNode source, +// final JsonNode target, false) +// { +// return +// } public static JsonPatch asJsonPatch(final JsonNode source, - final JsonNode target) + final JsonNode target) + { + return asJsonPatch(source, target, DiffOptions.DEFAULT_OPTIONS); + } + public static JsonPatch asJsonPatch(final JsonNode source, + final JsonNode target, final DiffOptions options) { BUNDLE.checkNotNull(source, "common.nullArgument"); BUNDLE.checkNotNull(target, "common.nullArgument"); final Map unchanged = getUnchangedValues(source, target); - final DiffProcessor processor = new DiffProcessor(unchanged); + final DiffProcessor processor = new DiffProcessor(unchanged, options); generateDiffs(processor, JsonPointer.empty(), source, target); return processor.getPatch(); @@ -103,10 +116,16 @@ public static JsonPatch asJsonPatch(final JsonNode source, * @return the patch as a {@link JsonNode} */ public static JsonNode asJson(final JsonNode source, final JsonNode target) + { + return asJson(source, target, DiffOptions.DEFAULT_OPTIONS); + } + + + public static JsonNode asJson(final JsonNode source, final JsonNode target, final DiffOptions options) { final String s; try { - s = MAPPER.writeValueAsString(asJsonPatch(source, target)); + s = MAPPER.writeValueAsString(asJsonPatch(source, target, options)); return MAPPER.readTree(s); } catch (IOException e) { throw new RuntimeException("cannot generate JSON diff", e); diff --git a/src/test/java/com/github/fge/jsonpatch/diff/JsonDiffTest.java b/src/test/java/com/github/fge/jsonpatch/diff/JsonDiffTest.java index 1a8d0ac5..00287f37 100644 --- a/src/test/java/com/github/fge/jsonpatch/diff/JsonDiffTest.java +++ b/src/test/java/com/github/fge/jsonpatch/diff/JsonDiffTest.java @@ -32,7 +32,8 @@ import java.util.Iterator; import java.util.List; -import static org.assertj.core.api.Assertions.assertThat; +import static com.github.fge.jsonpatch.diff.DiffProcessor.DIFF_DOESNT_REQUIRE_SOURCE; +import static org.assertj.core.api.Assertions.*; public final class JsonDiffTest { @@ -53,17 +54,20 @@ public Iterator getPatchesOnly() final List list = Lists.newArrayList(); for (final JsonNode node: testData) - list.add(new Object[] { node.get("first"), node.get("second") }); + list.add(new Object[] { + node.get("first"), node.get("second"), + node.has("options") ? getLiteralOptions(node.get("options")) : DiffOptions.DEFAULT_OPTIONS + }); return list.iterator(); } @Test(dataProvider = "getPatchesOnly") public void generatedPatchAppliesCleanly(final JsonNode first, - final JsonNode second) + final JsonNode second, final DiffOptions options) throws JsonPatchException { - final JsonPatch patch = JsonDiff.asJsonPatch(first, second); + final JsonPatch patch = JsonDiff.asJsonPatch(first, second, options); final JsonNode actual = patch.apply(first); assertThat(EQUIVALENCE.equivalent(second, actual)).overridingErrorMessage( @@ -82,21 +86,34 @@ public Iterator getLiteralPatches() continue; list.add(new Object[] { node.get("message").textValue(), node.get("first"), - node.get("second"), node.get("patch") + node.get("second"), node.get("patch"), + node.has("options") ? getLiteralOptions(node.get("options")) : DiffOptions.DEFAULT_OPTIONS }); } return list.iterator(); } + public DiffOptions getLiteralOptions(JsonNode jsonNode) { + DiffOptions.Builder builder = new DiffOptions.Builder(); + if (jsonNode.has("diffDoesntRequireSource")) { + if (jsonNode.get("diffDoesntRequireSource").booleanValue()){ + builder.diffDoesntRequireSource(); + } else { + builder.diffRequireSource(); + } + } + return builder.build(); + } + @Test( dataProvider = "getLiteralPatches", dependsOnMethods = "generatedPatchAppliesCleanly" ) public void generatedPatchesAreWhatIsExpected(final String message, - final JsonNode first, final JsonNode second, final JsonNode expected) + final JsonNode first, final JsonNode second, final JsonNode expected, final DiffOptions options) { - final JsonNode actual = JsonDiff.asJson(first, second); + final JsonNode actual = JsonDiff.asJson(first, second, options); assertThat(EQUIVALENCE.equivalent(expected, actual)).overridingErrorMessage( "patch is not what was expected\nscenario: %s\n" diff --git a/src/test/resources/jsonpatch/diff/diff.json b/src/test/resources/jsonpatch/diff/diff.json index 243aef12..d2e27336 100644 --- a/src/test/resources/jsonpatch/diff/diff.json +++ b/src/test/resources/jsonpatch/diff/diff.json @@ -134,5 +134,44 @@ "patch": [ { "op": "move", "path": "/c", "from": "/a" } ] + },{ + "message": "when diffDoesntRequireSource similar element is added", + "first": { + "a": "c" + }, + "second": { + "a": "c", + "d": "c" + }, + "patch": [ + { "op": "add", "path": "/d", "value": "c" } + ], + "options": { + "diffDoesntRequireSource": true + } + }, + { + "message": "when diffDoesntRequireSource similar element is removed then added", + "first": { "a": "b" }, + "second": { "c": "b" }, + "patch": [ + { "op": "remove", "path": "/a" }, + { "op": "add", "path": "/c", "value": "b" } + ], + "options": { + "diffDoesntRequireSource": true + } + + }, + { + "message": "with default options, similar element removed then added is moved instead", + "first": { "a": "b" }, + "second": { "c": "b" }, + "patch": [ + { "op": "move", "path": "/c", "from": "/a" } + ], + "options": { + } + } ] \ No newline at end of file