Skip to content

Commit 9f0585f

Browse files
author
Piotr Bugara
committed
#30 Ignore PathNotFoundException when removing fields which should be ignored, but they don't exist. Breaking diff process, when ignored fields contains invalid JsonPath or JsonPointer expression
1 parent 180e120 commit 9f0585f

File tree

2 files changed

+52
-10
lines changed

2 files changed

+52
-10
lines changed

src/main/java/com/gravity9/jsonpatch/diff/JsonDiff.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import com.gravity9.jsonpatch.JsonPatchMessages;
3535
import com.gravity9.jsonpatch.JsonPatchOperation;
3636
import com.gravity9.jsonpatch.RemoveOperation;
37+
import com.jayway.jsonpath.PathNotFoundException;
3738

3839
import javax.annotation.ParametersAreNonnullByDefault;
3940
import java.io.IOException;
@@ -110,10 +111,11 @@ public static JsonPatch asJsonPatch(final JsonNode source,
110111
* @param target the expected result after applying the patch
111112
* @param fieldsToIgnore list of JsonPath or JsonPointer paths which should be ignored when generating diff. Non-existing fields are ignored.
112113
* @return the patch as a {@link JsonPatch}
113-
* @since 1.9
114+
* @throws JsonPatchException if fieldsToIgnored not in valid JsonPath or JsonPointer format
115+
* @since 2.0.0
114116
*/
115117
public static JsonPatch asJsonPatchIgnoringFields(final JsonNode source,
116-
final JsonNode target, final List<String> fieldsToIgnore) {
118+
final JsonNode target, final List<String> fieldsToIgnore) throws JsonPatchException {
117119
BUNDLE.checkNotNull(source, "common.nullArgument");
118120
BUNDLE.checkNotNull(target, "common.nullArgument");
119121
final List<JsonPatchOperation> ignoredFieldsRemoveOperations = getJsonPatchRemoveOperationsForIgnoredFields(fieldsToIgnore);
@@ -129,23 +131,26 @@ public static JsonPatch asJsonPatchIgnoringFields(final JsonNode source,
129131
return processor.getPatch();
130132
}
131133

132-
private static JsonNode removeIgnoredFields(JsonNode node, List<JsonPatchOperation> ignoredFieldsRemoveOperations) {
134+
private static JsonNode removeIgnoredFields(JsonNode node, List<JsonPatchOperation> ignoredFieldsRemoveOperations) throws JsonPatchException {
133135
JsonNode nodeWithoutIgnoredFields = node;
134136
for (JsonPatchOperation operation : ignoredFieldsRemoveOperations) {
135137
nodeWithoutIgnoredFields = removeIgnoredFieldOrIgnore(nodeWithoutIgnoredFields, operation);
136138
}
137139
return nodeWithoutIgnoredFields;
138140
}
139141

140-
private static JsonNode removeIgnoredFieldOrIgnore(JsonNode nodeWithoutIgnoredFields, JsonPatchOperation operation) {
142+
private static JsonNode removeIgnoredFieldOrIgnore(JsonNode nodeWithoutIgnoredFields, JsonPatchOperation operation) throws JsonPatchException {
141143
try {
142144
List<JsonPatchOperation> operationsList = new ArrayList<>();
143145
operationsList.add(operation);
144146
return new JsonPatch(operationsList).apply(nodeWithoutIgnoredFields);
145147
} catch (JsonPatchException e) {
146-
// If remove for specific path failed, it means that node does not contain specific field which should be ignored.
148+
// If remove for specific path throws PathNotFound, it means that node does not contain specific field which should be ignored.
147149
// See more `empty patch if object does not contain ignored field` in diff.json file.
148-
return nodeWithoutIgnoredFields;
150+
if (e.getCause() instanceof PathNotFoundException) {
151+
return nodeWithoutIgnoredFields;
152+
}
153+
throw e;
149154
}
150155
}
151156

@@ -175,8 +180,10 @@ public static JsonNode asJson(final JsonNode source, final JsonNode target) {
175180
* @param target the expected result after applying the patch
176181
* @param fieldsToIgnore list of JsonPath or JsonPointer paths which should be ignored when generating diff. Non-existing fields are ignored.
177182
* @return the patch as a {@link JsonNode}
183+
* @throws JsonPatchException if fieldsToIgnored not in valid JsonPath or JsonPointer format
184+
* @since 2.0.0
178185
*/
179-
public static JsonNode asJsonIgnoringFields(final JsonNode source, final JsonNode target, List<String> fieldsToIgnore) {
186+
public static JsonNode asJsonIgnoringFields(final JsonNode source, final JsonNode target, List<String> fieldsToIgnore) throws JsonPatchException {
180187
final String s;
181188
try {
182189
s = MAPPER.writeValueAsString(asJsonPatchIgnoringFields(source, target, fieldsToIgnore));
@@ -229,9 +236,9 @@ private static void generateObjectDiffs(final DiffProcessor processor,
229236
final JsonPointer pointer, final ObjectNode source,
230237
final ObjectNode target) {
231238
final Set<String> firstFields
232-
= collect(source.fieldNames(), new TreeSet<String>());
239+
= collect(source.fieldNames(), new TreeSet<>());
233240
final Set<String> secondFields
234-
= collect(target.fieldNames(), new TreeSet<String>());
241+
= collect(target.fieldNames(), new TreeSet<>());
235242

236243
final Set<String> copy1 = new HashSet<>(firstFields);
237244
copy1.removeAll(secondFields);

src/test/java/com/gravity9/jsonpatch/diff/JsonDiffTest.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919

2020
package com.gravity9.jsonpatch.diff;
2121

22+
import com.fasterxml.jackson.core.JsonProcessingException;
2223
import com.fasterxml.jackson.databind.JsonNode;
24+
import com.fasterxml.jackson.databind.ObjectMapper;
2325
import com.github.fge.jackson.JsonLoader;
2426
import com.github.fge.jackson.JsonNumEquals;
2527
import com.google.common.collect.Lists;
@@ -33,6 +35,7 @@
3335
import org.testng.annotations.Test;
3436

3537
import static org.assertj.core.api.Assertions.assertThat;
38+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
3639

3740
public final class JsonDiffTest {
3841

@@ -122,7 +125,7 @@ public Iterator<Object[]> getDiffsWithIgnoredFields() {
122125
)
123126
public void generatedPatchesIgnoreFields(final String message,
124127
final JsonNode first, final JsonNode second, final JsonNode expected,
125-
final JsonNode ignoreFields) {
128+
final JsonNode ignoreFields) throws JsonPatchException {
126129

127130
final List<String> ignoreFieldsList = new ArrayList<>();
128131
final Iterator<JsonNode> ignoreFieldsIterator = ignoreFields.elements();
@@ -137,4 +140,36 @@ public void generatedPatchesIgnoreFields(final String message,
137140
+ "expected: %s\nactual: %s\n", message, expected, actual
138141
).isTrue();
139142
}
143+
144+
@DataProvider
145+
public Iterator<Object[]> getInvalidIgnoreFieldsExpressions() {
146+
final List<Object[]> list = Lists.newArrayList();
147+
list.add(new Object[]{
148+
"$.a[(@.length-1)]", "Could not parse token starting at position 3. Expected ?, ', 0-9, * "
149+
});
150+
list.add(new Object[]{
151+
"/a/?", "Invalid path, `?` are not allowed in JsonPointer expressions."
152+
});
153+
return list.iterator();
154+
}
155+
156+
@Test(
157+
dataProvider = "getInvalidIgnoreFieldsExpressions"
158+
)
159+
public void shouldNotPerformDiffWhenIgnoreFieldsContainsInvalidExpression(String ignoreFieldsExpression, String expectedExceptionMessage) throws JsonProcessingException {
160+
// given
161+
JsonNode source = new ObjectMapper().readTree("{\"a\": \"1\"}");
162+
JsonNode target = new ObjectMapper().readTree("{\"a\": \"1\"}");
163+
List<String> ignoreFields = new ArrayList<>();
164+
ignoreFields.add(ignoreFieldsExpression);
165+
166+
// when
167+
assertThatThrownBy(() -> JsonDiff.asJsonIgnoringFields(source, target, ignoreFields))
168+
.isExactlyInstanceOf(JsonPatchException.class)
169+
.hasMessageStartingWith(expectedExceptionMessage);
170+
171+
assertThatThrownBy(() -> JsonDiff.asJsonPatchIgnoringFields(source, target, ignoreFields))
172+
.isExactlyInstanceOf(JsonPatchException.class)
173+
.hasMessageStartingWith(expectedExceptionMessage);
174+
}
140175
}

0 commit comments

Comments
 (0)