Skip to content

Patch history #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Adding functionality to diff json objects and include history.
  • Loading branch information
Roling, Luke committed Apr 21, 2015
commit 46cfcfdfc9df7eb6d78a49c4c987b77818ce786f
124 changes: 56 additions & 68 deletions src/main/java/com/github/fge/jsonpatch/diff/DiffOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,131 +33,119 @@ final class DiffOperation
private final Type type;
/* An op's "from", if any */
private final JsonPointer from;
/* Value displaced by this operation, if any */
private final JsonNode oldValue;
/* Value at op's from, if any */
private final JsonNode fromValue;
/* An op's "path", if any */
private final JsonPointer path;
/* Value at op's from, if any */
private final JsonNode pathValue;
/* An op's "value", if any */
private final JsonNode value;

static DiffOperation add(final JsonPointer path,
final JsonNode value)
{
return new DiffOperation(Type.ADD, null, null, path, value);
static DiffOperation add(final JsonPointer path, final JsonNode pathValue, final JsonNode value) {
return new DiffOperation(Type.ADD, null, null, path, pathValue, value);
}

static DiffOperation copy(final JsonPointer from,
final JsonPointer path, final JsonNode value)
{
return new DiffOperation(Type.COPY, from, null, path,
value);
static DiffOperation copy(final JsonPointer from, final JsonNode fromValue,
final JsonPointer path, final JsonNode pathValue) {
return new DiffOperation(Type.COPY, from, fromValue, path, pathValue, null);
}

static DiffOperation move(final JsonPointer from,
final JsonNode oldValue, final JsonPointer path,
final JsonNode value)
{
return new DiffOperation(Type.MOVE, from, oldValue, path,
value);
static DiffOperation move(final JsonPointer from, final JsonNode fromValue,
final JsonPointer path, final JsonNode pathValue) {
return new DiffOperation(Type.MOVE, from, fromValue, path, pathValue, null);
}

static DiffOperation remove(final JsonPointer from,
final JsonNode oldValue)
{
return new DiffOperation(Type.REMOVE, from, oldValue, null, null);
static DiffOperation remove(final JsonPointer path, final JsonNode pathValue) {
return new DiffOperation(Type.REMOVE, null, null, path, pathValue, null);
}

static DiffOperation replace(final JsonPointer from,
final JsonNode oldValue, final JsonNode value)
{
return new DiffOperation(Type.REPLACE, from, oldValue, null,
value);
static DiffOperation replace(final JsonPointer path, final JsonNode pathValue, final JsonNode value) {
return new DiffOperation(Type.REPLACE, null, null, path, pathValue, value);
}

private DiffOperation(final Type type, final JsonPointer from,
final JsonNode oldValue, final JsonPointer path,
final JsonNode value)
{
private DiffOperation(final Type type, final JsonPointer from, final JsonNode fromValue,
final JsonPointer path, final JsonNode pathValue, final JsonNode value) {
this.type = type;
this.from = from;
this.oldValue = oldValue;
this.fromValue = fromValue;
this.path = path;
this.pathValue = pathValue;
this.value = value;
}

Type getType()
{
return type;
}
Type getType() { return type; }

JsonPointer getFrom()
{
return from;
}

JsonNode getOldValue()
JsonNode getFromValue()
{
return oldValue;
return fromValue;
}

JsonPointer getPath()
{
return path;
}

JsonNode getPathValue() { return pathValue; }

JsonNode getValue()
{
return value;
}

JsonPatchOperation asJsonPatchOperation()
JsonPatchOperation asJsonPatchOperation(final boolean includeHistory)
{
return type.toOperation(this);
return type.toOperation(this, includeHistory);
}

enum Type {
ADD
{
@Override
JsonPatchOperation toOperation(final DiffOperation op)
{
return new AddOperation(op.path, op.value);
}
},
COPY
{
ADD {
@Override
JsonPatchOperation toOperation(final DiffOperation op)
{
return new CopyOperation(op.from, op.path);
JsonPatchOperation toOperation(final DiffOperation op, final boolean includeHistory) {
return includeHistory ?
new AddOperation(op.path, op.value, op.pathValue) :
new AddOperation(op.path, op.value);
}
},
MOVE
{
COPY {
@Override
JsonPatchOperation toOperation(final DiffOperation op)
{
return new MoveOperation(op.from, op.path);
JsonPatchOperation toOperation(final DiffOperation op, final boolean includeHistory) {
return includeHistory ?
new CopyOperation(op.from, op.path, op.fromValue, op.pathValue) :
new CopyOperation(op.from, op.path);
}
},
REMOVE
{
MOVE {
@Override
JsonPatchOperation toOperation(final DiffOperation op)
{
return new RemoveOperation(op.from);
JsonPatchOperation toOperation(final DiffOperation op, final boolean includeHistory) {
return includeHistory ?
new MoveOperation(op.from, op.path, op.fromValue, op.pathValue) :
new MoveOperation(op.from, op.path);
}
},
REPLACE
REMOVE
{
@Override
JsonPatchOperation toOperation(final DiffOperation op)
{
return new ReplaceOperation(op.from, op.value);
JsonPatchOperation toOperation(final DiffOperation op, final boolean includeHistory) {
return includeHistory ?
new RemoveOperation(op.path, op.pathValue) :
new RemoveOperation(op.path);
}
},
;
REPLACE {
@Override
JsonPatchOperation toOperation(final DiffOperation op, final boolean includeHistory) {
return includeHistory ?
new ReplaceOperation(op.path, op.value, op.pathValue) :
new ReplaceOperation(op.path, op.value);
}
};

abstract JsonPatchOperation toOperation(final DiffOperation op);
abstract JsonPatchOperation toOperation(final DiffOperation op, final boolean includeHistory);
}
}
31 changes: 15 additions & 16 deletions src/main/java/com/github/fge/jsonpatch/diff/DiffProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,41 +48,41 @@ final class DiffProcessor
this.unchanged = ImmutableMap.copyOf(unchanged);
}

void valueReplaced(final JsonPointer pointer, final JsonNode oldValue,
final JsonNode newValue)
void valueReplaced(final JsonPointer path, final JsonNode pathValue, final JsonNode newValue)
{
diffs.add(DiffOperation.replace(pointer, oldValue, newValue));
diffs.add(DiffOperation.replace(path, pathValue, newValue));
}

void valueRemoved(final JsonPointer pointer, final JsonNode value)
void valueRemoved(final JsonPointer path, final JsonNode pathValue)
{
diffs.add(DiffOperation.remove(pointer, value));
diffs.add(DiffOperation.remove(path, pathValue));
}

void valueAdded(final JsonPointer pointer, final JsonNode value)
void valueAdded(final JsonPointer path, final JsonNode newValue)
{
final int removalIndex = findPreviouslyRemoved(value);
JsonNode pathValue = unchanged.get(path);

final int removalIndex = findPreviouslyRemoved(newValue);
if (removalIndex != -1) {
final DiffOperation removed = diffs.get(removalIndex);
diffs.remove(removalIndex);
diffs.add(DiffOperation.move(removed.getFrom(),
value, pointer, value));
diffs.add(DiffOperation.move(removed.getPath(), removed.getPathValue(), path, pathValue));
return;
}
final JsonPointer ptr = findUnchangedValue(value);
final JsonPointer ptr = findUnchangedValue(newValue);
final DiffOperation op = ptr != null
? DiffOperation.copy(ptr, pointer, value)
: DiffOperation.add(pointer, value);
? DiffOperation.copy(ptr, unchanged.get(ptr), path, pathValue)
: DiffOperation.add(path, pathValue, newValue);

diffs.add(op);
}

JsonPatch getPatch()
JsonPatch getPatch(final boolean includeHistory)
{
final List<JsonPatchOperation> list = Lists.newArrayList();

for (final DiffOperation op: diffs)
list.add(op.asJsonPatchOperation());
list.add(op.asJsonPatchOperation(includeHistory));

return new JsonPatch(list);
}
Expand All @@ -105,8 +105,7 @@ private int findPreviouslyRemoved(final JsonNode value)

for (int i = 0; i < diffs.size(); i++) {
op = diffs.get(i);
if (op.getType() == DiffOperation.Type.REMOVE
&& predicate.apply(op.getOldValue()))
if (op.getType() == DiffOperation.Type.REMOVE && predicate.apply(op.getPathValue()))
return i;
}
return -1;
Expand Down
11 changes: 6 additions & 5 deletions src/main/java/com/github/fge/jsonpatch/diff/JsonDiff.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ private JsonDiff()
*
* @param source the node to be patched
* @param target the expected result after applying the patch
* @param includeHistory flag to determine if original values are included with operation
* @return the patch as a {@link JsonPatch}
*
* @since 1.9
*/
public static JsonPatch asJsonPatch(final JsonNode source,
final JsonNode target)
public static JsonPatch asJsonPatch(final JsonNode source, final JsonNode target, final boolean includeHistory)
{
BUNDLE.checkNotNull(source, "common.nullArgument");
BUNDLE.checkNotNull(target, "common.nullArgument");
Expand All @@ -97,7 +97,7 @@ public static JsonPatch asJsonPatch(final JsonNode source,
final DiffProcessor processor = new DiffProcessor(unchanged);

generateDiffs(processor, JsonPointer.empty(), source, target);
return processor.getPatch();
return processor.getPatch(includeHistory);
}

/**
Expand All @@ -106,13 +106,14 @@ public static JsonPatch asJsonPatch(final JsonNode source,
*
* @param source the node to be patched
* @param target the expected result after applying the patch
* @param includeHistory flag to determine if original values are included with operation
* @return the patch as a {@link JsonNode}
*/
public static JsonNode asJson(final JsonNode source, final JsonNode target)
public static JsonNode asJson(final JsonNode source, final JsonNode target, final boolean includeHistory)
{
final String s;
try {
s = MAPPER.writeValueAsString(asJsonPatch(source, target));
s = MAPPER.writeValueAsString(asJsonPatch(source, target, includeHistory));
return MAPPER.readTree(s);
} catch (IOException e) {
throw new RuntimeException("cannot generate JSON diff", e);
Expand Down
4 changes: 2 additions & 2 deletions src/test/java/com/github/fge/jsonpatch/diff/JsonDiffTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void generatedPatchAppliesCleanly(final JsonNode first,
final JsonNode second)
throws JsonPatchException
{
final JsonPatch patch = JsonDiff.asJsonPatch(first, second);
final JsonPatch patch = JsonDiff.asJsonPatch(first, second, false);
final Predicate<JsonNode> predicate = EQUIVALENCE.equivalentTo(second);
final JsonNode actual = patch.apply(first);

Expand Down Expand Up @@ -100,7 +100,7 @@ public Iterator<Object[]> getLiteralPatches()
public void generatedPatchesAreWhatIsExpected(final String message,
final JsonNode first, final JsonNode second, final JsonNode expected)
{
final JsonNode actual = JsonDiff.asJson(first, second);
final JsonNode actual = JsonDiff.asJson(first, second, false);
final Predicate<JsonNode> predicate
= EQUIVALENCE.equivalentTo(expected);

Expand Down