diff --git a/Simperium/src/androidTestSupport/java/com/simperium/JSONDiffTest.java b/Simperium/src/androidTestSupport/java/com/simperium/JSONDiffTest.java index 92d91331..d5b5477a 100644 --- a/Simperium/src/androidTestSupport/java/com/simperium/JSONDiffTest.java +++ b/Simperium/src/androidTestSupport/java/com/simperium/JSONDiffTest.java @@ -338,6 +338,24 @@ public void testTransformStringDiff() } + public void testInvalidStringTransformThrowsException() + throws Exception { + String origin = "Line 1\nLine 2\nReplace me"; + try + { + JSONObject transformed = JSONDiff.transform( + "=14\t+Before%0A\t=10\t+%0AAfter", + "=14\t-10\t+BYE", + origin + ); + fail("Patch transform should have failed."); + } + catch(Exception e) + { + // Test passed + } + } + public void testTransformObjectDiffChangeRemovedKey() throws Exception { diff --git a/Simperium/src/main/java/com/simperium/client/Bucket.java b/Simperium/src/main/java/com/simperium/client/Bucket.java index 3c600ba1..1058071e 100644 --- a/Simperium/src/main/java/com/simperium/client/Bucket.java +++ b/Simperium/src/main/java/com/simperium/client/Bucket.java @@ -927,6 +927,7 @@ public Ghost applyRemoteChange(RemoteChange change) try { T object; Boolean isNew; + Boolean shouldUpdateObject = true; if (change.isAddOperation()) { object = newObject(change.getKey()); @@ -962,7 +963,6 @@ public Ghost applyRemoteChange(RemoteChange change) mSchema.updateWithDefaults(object, updatedProperties); addObject(object); } else { - if (localModifications != null && localModifications.length() > 0) { try { JSONObject incomingDiff = change.getPatch(); @@ -971,15 +971,17 @@ public Ghost applyRemoteChange(RemoteChange change) JSONObject transformedDiff = JSONDiff.transform(localDiff, incomingDiff, currentProperties); updatedProperties = JSONDiff.apply(updatedProperties, transformedDiff); - } catch (JSONException | IllegalArgumentException e) { - // could not transform properties - // continue with updated properties + // We couldn't merge the local and remote changes. + // Hold off on updating the object so that the local change can sync + shouldUpdateObject = false; } } - mSchema.update(object, updatedProperties); - updateObject(object); + if (shouldUpdateObject) { + mSchema.update(object, updatedProperties); + updateObject(object); + } } } catch(SimperiumException e) { diff --git a/Simperium/src/main/java/com/simperium/util/JSONDiff.java b/Simperium/src/main/java/com/simperium/util/JSONDiff.java index da0d8783..68f66910 100644 --- a/Simperium/src/main/java/com/simperium/util/JSONDiff.java +++ b/Simperium/src/main/java/com/simperium/util/JSONDiff.java @@ -43,8 +43,16 @@ public static JSONObject transform(String o_diff, String diff, String source) LinkedList patches = dmp.patch_make(source, dmp.diff_fromDelta(source, diff)); String text = (String) dmp.patch_apply(patches, source)[0]; - String combined = (String) dmp.patch_apply(o_patches, text)[0]; + Object[] appliedPatch = dmp.patch_apply(o_patches, text); + boolean[] results = (boolean[]) appliedPatch[1]; + for (boolean result : results) { + if (!result) { + throw new JSONException("Could not cleanly transform patch."); + } + } + + String combined = (String)appliedPatch[0]; if (text.equals(combined)) { // text is the same, return empty diff return transformed;