From 9195d887d54a094458f165aee9d4720933d7e52d Mon Sep 17 00:00:00 2001 From: Dan Douglas Date: Wed, 27 Aug 2025 16:20:25 -0700 Subject: [PATCH 1/3] Update code to pick up 0.5.0 changes from zjsonpatch --- .github/dependabot.yml | 6 + CONTRIBUTING.md | 8 +- NOTICE | 11 +- README.md | 56 ++++-- pom.xml | 58 +++--- .../java/com/ebay/bsonpatch/BsonDiff.java | 11 +- .../java/com/ebay/bsonpatch/BsonPatch.java | 26 ++- .../BsonPatchApplicationException.java | 18 +- .../ebay/bsonpatch/CopyingApplyProcessor.java | 9 +- .../ebay/bsonpatch/InPlaceApplyProcessor.java | 34 ++-- .../java/com/ebay/bsonpatch/JsonPointer.java | 165 +++++++++++++++--- .../java/com/ebay/bsonpatch/Operation.java | 2 +- .../java/com/ebay/bsonpatch/AbstractTest.java | 55 ++++-- .../com/ebay/bsonpatch/AddOperationTest.java | 4 +- src/test/java/com/ebay/bsonpatch/ApiTest.java | 12 +- .../com/ebay/bsonpatch/CompatibilityTest.java | 17 +- .../com/ebay/bsonpatch/CopyOperationTest.java | 4 +- .../com/ebay/bsonpatch/JsLibSamplesTest.java | 4 +- .../java/com/ebay/bsonpatch/JsonDiffTest.java | 16 +- .../com/ebay/bsonpatch/JsonDiffTest2.java | 14 +- .../com/ebay/bsonpatch/JsonPointerTest.java | 66 +++++-- .../com/ebay/bsonpatch/MoveOperationTest.java | 12 +- .../com/ebay/bsonpatch/PatchTestCase.java | 11 +- .../java/com/ebay/bsonpatch/RFC6901Tests.java | 4 +- .../ebay/bsonpatch/RemoveOperationTest.java | 4 +- .../ebay/bsonpatch/ReplaceOperationTest.java | 4 +- .../ebay/bsonpatch/Rfc6902SamplesTest.java | 4 +- .../com/ebay/bsonpatch/TestDataGenerator.java | 8 +- .../ebay/bsonpatch/TestNodesEmissionTest.java | 10 +- .../com/ebay/bsonpatch/TestOperationTest.java | 4 +- .../java/com/ebay/bsonpatch/TestUtils.java | 34 +++- .../com/ebay/bsonpatch/ValidationTest.java | 40 +++++ .../resources/testdata/invalid-patches.json | 37 ++++ .../resources/testdata/js-libs-samples.json | 9 +- .../testdata/json-pointer-key-refs.json | 26 +++ src/test/resources/testdata/replace.json | 3 +- 36 files changed, 590 insertions(+), 216 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 src/test/java/com/ebay/bsonpatch/ValidationTest.java create mode 100644 src/test/resources/testdata/invalid-patches.json create mode 100644 src/test/resources/testdata/json-pointer-key-refs.json diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..ffc0b7d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: maven + directory: / + schedule: + interval: weekly diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a38abf8..8a21321 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,11 +8,11 @@ The following guidelines apply to all contributors. ### Making Changes -* Fork the `monstor-cdc/bsonpatch` repository +* Fork the `bsonpatch/bsonpatch` repository * Make your changes and push them to a topic branch in your fork * See our commit message guidelines further down in this document -* Submit a pull request to the `monstor-cdc/bsonpatch` repository -* Update `monstor-cdc/bsonpatch` GITHUB issue with the generated pull request link +* Submit a pull request to the `bsonpatch/bsonpatch` repository +* Update `bsonpatch/bsonpatch` GITHUB issue with the generated pull request link ### General Guidelines @@ -34,7 +34,7 @@ The following guidelines apply to all contributors. * The first line should be limited to 50 characters and should not end in a period. * Subsequent lines should be wrapped at 72 characters. -* Put `Closes: https://github.com/eBay/bsonpatch/issues/XXX` line at the very +* Put `Closes: https://github.com/bsonpatch/bsonpatch/issues/XXX` line at the very end (where `XXX` is the actual issue number) if the proposed change is relevant to a tracked issue. Note: In Git commits the first line of the commit message has special diff --git a/NOTICE b/NOTICE index 82ea274..1846345 100644 --- a/NOTICE +++ b/NOTICE @@ -1,9 +1,10 @@ bsonpatch library -Copyright 2017,2018,2022 eBay, Inc. +Copyright 2025 -This product includes software developed at -eBay, Inc. (https://www.ebay.com/). +This software was ported (forked, renamed, repackaged, modified) from +the bsonpatch project, developed at ebay.com +https://github.com/eBay/bsonpatch -This software was ported (copied, renamed, repackaged, modified) from +Which, in turn, was ported (forked, renamed, repackaged, modified) from the zjsonpatch project, developed at flipkart.com -https://github.com/flipkart-incubator/zjsonpatch. +https://github.com/flipkart-incubator/zjsonpatch diff --git a/README.md b/README.md index 9d6ed95..59ff5fb 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,39 @@ -# This is an implementation of [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) written in Java. +# This is an implementation of [RFC 6902 JSON Patch](https://datatracker.ietf.org/doc/html/rfc6902) written in Java with extended BSON pointer. This [JSON Patch](http://jsonpatch.com) implementation works directly with [BSON documents](http://bsonspec.org/) using the [MongoDB Java driver implementation of BSON](https://www.mongodb.com/json-and-bson). -The code here was ported (copied, renamed, repackaged, modified) from the [zjsonpatch project](https://github.com/flipkart-incubator/zjsonpatch). +The code here was forked (copied, renamed, repackaged, modified) from [eBay bsonpatch project](https://github.com/eBay/bsonpatch) which, in turn, was ported (forked, renamed, repackaged, modified) from the [zjsonpatch project](https://github.com/flipkart-incubator/zjsonpatch). ## Description & Use-Cases - Java Library to find / apply JSON Patches according to [RFC 6902](https://datatracker.ietf.org/doc/html/rfc6902). - JSON Patch defines a JSON document structure for representing changes to a JSON document. - It can be used to avoid sending a whole document when only a part has changed, thus reducing network bandwidth requirements if data (in JSON format) is required to send across multiple systems over network or in case of multi DC transfer. -- When used in combination with the HTTP PATCH method as per [RFC 5789 HTTP PATCH](https://datatracker.ietf.org/doc/html/rfc5789), it will do partial updates for HTTP APIs in a standard way. +- When used in combination with the HTTP PATCH method as per [RFC 5789 HTTP PATCH](https://datatracker.ietf.org/doc/html/rfc5789), it will do partial updates for HTTP APIs in a standard way. +- Extended JSON pointer functionality (i.e. reference array elements via a key): `/array/id=123/data` + - The user has to ensure that a unique field is used as a reference key. Should there be more than one array + element matching the given key-value pair, the first element will be selected. + - Key based referencing may be slow for large arrays. Hence, standard index based array pointers should be used for large arrays. - This library compares two [BsonValue](https://mongodb.github.io/mongo-java-driver/3.12/javadoc/org/bson/BsonValue.html) inputs and produces a [BsonArray](https://mongodb.github.io/mongo-java-driver/3.12/javadoc/org/bson/BsonArray.html) of the changes. ### Compatible with : Java 8 and above all versions ## Complexity -- To find JsonPatch : Ω(N+M) ,N and M represents number of keys in first and second JSON respectively / O(summation of la*lb) where la , lb represents JSON Array of length la / lb of against same key in first and second JSON ,since LCS is used to find difference between 2 JSON arrays there of order of quadratic. +- To find JsonPatch : Ω(N+M), N and M represents number of keys in first and second JSON respectively / O(summation of la*lb) where la , lb represents JSON Array of length la / lb of against same key in first and second JSON ,since LCS is used to find difference between 2 JSON arrays there of order of quadratic. - To Optimize Diffs ( compact move and remove into Move ) : Ω(D) / O(D*D) where D represents number of diffs obtained before compaction into Move operation. - To Apply Diff : O(D) where D represents number of diffs ### How to use: -### Current Version : 0.4.12 +### Current Version : 0.5.0 Add following to `` section of your pom.xml - ```xml - com.ebay.bsonpatch + io.github.bsonpatch bsonpatch - 0.4.12 + 0.5.0 ``` @@ -78,6 +82,33 @@ Following patch will be returned: ``` here `"op"` represents the operation (`"move"`), `"from"` represent path from where value should be moved, `"path"` represents where value should be moved. The value that is moved is taken as the content at the `"from"` path. +### Extended JSON Pointer Example +JSON +```json +{ + "a": [ + { + "id": 1, + "data": "abc" + }, + { + "id": 2, + "data": "def" + } + ] +} +``` + +JSON path +```jsonpath +/a/id=2/data +``` + +Following JSON would be returned +```json +"def" +``` + ### Apply Json Patch In-Place ```xml BsonPatch.applyInPlace(BsonArray patch, BsonValue source); @@ -85,19 +116,24 @@ BsonPatch.applyInPlace(BsonArray patch, BsonValue source); Given a `patch`, it will apply it to the `source` BSON mutating the instance, opposed to `BsonPatch.apply` which returns a new instance with the patch applied, leaving the `source` unchanged. +This is an extension to the RFC, and has some additional limitations. Specifically, the source document cannot be fully change in place. This means the following operations are not supported: +* `remove` with an empty or root path; +* `replace` with an empty or root path; +* `move`, `add` or `copy` targeting an empty or root path. + ### Tests: 1. 100+ selective hardcoded different input JSONs , with their driver test classes present under /test directory. 2. Apart from selective input, a deterministic random JSON generator is present under ( TestDataGenerator.java ), and its driver test class method is JsonDiffTest.testGeneratedJsonDiff(). -#### *** Tests can only show presence of bugs and not their absence *** +#### *** Tests can only show the presence of bugs and not their absence *** ## Get Involved * **Contributing**: Pull requests are welcome! * Read [`CONTRIBUTING.md`](CONTRIBUTING.md) - * Submit [github issues](https://github.com/eBay/bsonpatch/issues) for any feature enhancements, bugs or documentation problems + * Submit [github issues](https://github.com/bsonpatch/bsonpatch/issues) for any feature enhancements, bugs or documentation problems -* **Support**: Questions/comments can posted as [github issues](https://github.com/eBay/bsonpatch/issues) +* **Support**: Questions/comments can posted as [github issues](https://github.com/bsonpatch/bsonpatch/issues) ## Maintainers diff --git a/pom.xml b/pom.xml index e21982e..a8ce635 100644 --- a/pom.xml +++ b/pom.xml @@ -4,29 +4,25 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.ebay.bsonpatch + io.github.dandoug bsonpatch - 0.4.12 + 0.5.0-SNAPSHOT jar ${project.groupId}:${project.artifactId} Java Library to find / apply JSON Patches according to RFC 6902 against BsonValues - https://github.com/ebay/bsonpatch/ - - - scm:git:git://github.com/eBay/bsonpatch.git - scm:git:ssh://github.com/eBay/bsonpatch.git - https://github.com/ebay/bsonpatch - HEAD - + https://github.com/dandoug/bsonpatch/ + + + scm:git:git://github.com/dandoug/bsonpatch.git + scm:git:ssh://github.com:dandoug/bsonpatch.git + https://github.com/dandoug/bsonpatch/tree/master + dandoug Dan Douglas - ddouglas@skibums.org - eBay - https://www.ebay.com @@ -40,6 +36,9 @@ UTF-8 + 1.8 + 1.8 + 5.13.4 @@ -47,7 +46,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.14.0 1.8 1.8 @@ -61,7 +60,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.1 attach-sources @@ -137,25 +136,32 @@ org.mongodb mongo-java-driver - 3.12.10 + 3.12.14 + org.apache.commons commons-collections4 - 4.3 + 4.5.0 + test - - test commons-io commons-io - 2.7 - - - test - junit - junit - 4.13.1 + 2.20.0 + test + + org.junit.jupiter + junit-jupiter-params + ${junitVersion} + test + + + org.junit.vintage + junit-vintage-engine + ${junitVersion} + test + diff --git a/src/main/java/com/ebay/bsonpatch/BsonDiff.java b/src/main/java/com/ebay/bsonpatch/BsonDiff.java index 6c50735..2a572ce 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonDiff.java +++ b/src/main/java/com/ebay/bsonpatch/BsonDiff.java @@ -19,19 +19,14 @@ package com.ebay.bsonpatch; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - import org.apache.commons.collections4.ListUtils; import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonString; import org.bson.BsonValue; +import java.util.*; + public final class BsonDiff { @@ -266,7 +261,7 @@ private static JsonPointer updatePathWithCounters(List counters, JsonPo int value = counters.get(i); if (value != 0) { int currValue = tokens.get(i).getIndex(); - tokens.set(i, new JsonPointer.RefToken(Integer.toString(currValue + value))); + tokens.set(i, JsonPointer.RefToken.parse(Integer.toString(currValue + value))); } } return new JsonPointer(tokens); diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatch.java b/src/main/java/com/ebay/bsonpatch/BsonPatch.java index de86fa3..3cd8328 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonPatch.java +++ b/src/main/java/com/ebay/bsonpatch/BsonPatch.java @@ -19,23 +19,33 @@ package com.ebay.bsonpatch; -import static com.ebay.bsonpatch.InPlaceApplyProcessor.cloneBsonValue; +import org.bson.BsonArray; +import org.bson.BsonNull; +import org.bson.BsonValue; import java.util.EnumSet; import java.util.Iterator; -import org.bson.BsonArray; -import org.bson.BsonNull; -import org.bson.BsonValue; +import static com.ebay.bsonpatch.InPlaceApplyProcessor.cloneBsonValue; public final class BsonPatch { private BsonPatch() {} + private static BsonValue getPatchStringAttr(BsonValue bsonNode, String attr) { + BsonValue child = getPatchAttr(bsonNode, attr); + + if (!child.isString()) + throw new InvalidBsonPatchException("Invalid JSON Patch payload (non-text '" + attr + "' field)"); + + return child; + } + private static BsonValue getPatchAttr(BsonValue bsonNode, String attr) { BsonValue child = bsonNode.asDocument().get(attr); if (child == null) throw new InvalidBsonPatchException("Invalid BSON Patch payload (missing '" + attr + "' field)"); + return child; } @@ -54,8 +64,8 @@ private static void process(BsonArray patch, BsonPatchProcessor processor, EnumS while (operations.hasNext()) { BsonValue bsonNode = operations.next(); if (!bsonNode.isDocument()) throw new InvalidBsonPatchException("Invalid BSON Patch payload (not an object)"); - Operation operation = Operation.fromRfcName(getPatchAttr(bsonNode, Constants.OP).asString().getValue().replaceAll("\"", "")); - JsonPointer path = JsonPointer.parse(getPatchAttr(bsonNode, Constants.PATH).asString().getValue()); + Operation operation = Operation.fromRfcName(getPatchStringAttr(bsonNode, Constants.OP).asString().getValue().replaceAll("\"", "")); + JsonPointer path = JsonPointer.parse(getPatchStringAttr(bsonNode, Constants.PATH).asString().getValue()); try { switch (operation) { @@ -85,13 +95,13 @@ private static void process(BsonArray patch, BsonPatchProcessor processor, EnumS } case MOVE: { - JsonPointer fromPath = JsonPointer.parse(getPatchAttr(bsonNode, Constants.FROM).asString().getValue()); + JsonPointer fromPath = JsonPointer.parse(getPatchStringAttr(bsonNode, Constants.FROM).asString().getValue()); processor.move(fromPath, path); break; } case COPY: { - JsonPointer fromPath = JsonPointer.parse(getPatchAttr(bsonNode, Constants.FROM).asString().getValue()); + JsonPointer fromPath = JsonPointer.parse(getPatchStringAttr(bsonNode, Constants.FROM).asString().getValue()); processor.copy(fromPath, path); break; } diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java b/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java index e589487..1a0bb6e 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java +++ b/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java @@ -21,17 +21,25 @@ public class BsonPatchApplicationException extends RuntimeException { private static final long serialVersionUID = 7562538769544371424L; - - Operation operation; - JsonPointer path; + + final Operation operation; + final JsonPointer path; public BsonPatchApplicationException(String message, Operation operation, JsonPointer path) { super(message); this.operation = operation; this.path = path; } - - @Override + + public Operation getOperation() { + return operation; + } + + public JsonPointer getPath() { + return path; + } + + @Override public String toString() { StringBuilder sb = new StringBuilder(); if (operation != null) sb.append('[').append(operation).append(" Operation] "); diff --git a/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java b/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java index e12bd51..faaf3f3 100644 --- a/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java +++ b/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java @@ -22,6 +22,7 @@ import org.bson.BsonBinary; import org.bson.BsonJavaScriptWithScope; import org.bson.BsonValue; + import java.util.EnumSet; class CopyingApplyProcessor extends InPlaceApplyProcessor { @@ -32,8 +33,12 @@ class CopyingApplyProcessor extends InPlaceApplyProcessor { CopyingApplyProcessor(BsonValue target, EnumSet flags) { super(deepCopy(target), flags); - } - + } + + @Override + protected boolean allowRootReplacement() { + return true; + } static BsonValue deepCopy(BsonValue source) { BsonValue result; switch (source.getBsonType()) { diff --git a/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java b/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java index c62fc71..765117e 100644 --- a/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java +++ b/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java @@ -19,13 +19,9 @@ package com.ebay.bsonpatch; -import java.util.EnumSet; +import org.bson.*; -import org.bson.BsonArray; -import org.bson.BsonBinary; -import org.bson.BsonDocument; -import org.bson.BsonJavaScriptWithScope; -import org.bson.BsonValue; +import java.util.EnumSet; class InPlaceApplyProcessor implements BsonPatchProcessor { @@ -45,6 +41,10 @@ public BsonValue result() { return target; } + protected boolean allowRootReplacement() { + return false; + } + @Override public void move(JsonPointer fromPath, JsonPointer toPath) throws JsonPointerEvaluationException { BsonValue valueNode = fromPath.evaluate(target); @@ -95,6 +95,8 @@ public void add(JsonPointer path, BsonValue value) throws JsonPointerEvaluationE @Override public void replace(JsonPointer path, BsonValue value) throws JsonPointerEvaluationException { if (path.isRoot()) { + if (!allowRootReplacement()) + throw new BsonPatchApplicationException("Cannot replace root document", Operation.REPLACE, path); target = value; return; } @@ -170,17 +172,19 @@ static BsonValue cloneBsonValue(BsonValue from) { } private void set(JsonPointer path, BsonValue value, Operation forOp) throws JsonPointerEvaluationException { - if (path.isRoot()) + if (path.isRoot()) { + if (!allowRootReplacement()) + throw new BsonPatchApplicationException("Cannot replace root document", forOp, path); target = value; - else { - BsonValue parentNode = path.getParent().evaluate(target); - if (!parentNode.isDocument() && !parentNode.isArray()) - throw new BsonPatchApplicationException("Cannot reference past scalar value", forOp, path.getParent()); - else if (parentNode.isArray()) - addToArray(path, value, parentNode); - else - addToObject(path, parentNode, value); + return; } + BsonValue parentNode = path.getParent().evaluate(target); + if (parentNode.getBsonType() != BsonType.DOCUMENT && parentNode.getBsonType() != BsonType.ARRAY) + throw new BsonPatchApplicationException("Cannot reference past scalar value", forOp, path.getParent()); + else if (parentNode.isArray()) + addToArray(path, value, parentNode); + else + addToObject(path, parentNode, value); } private void addToObject(JsonPointer path, BsonValue node, BsonValue value) { diff --git a/src/main/java/com/ebay/bsonpatch/JsonPointer.java b/src/main/java/com/ebay/bsonpatch/JsonPointer.java index 1fe9bfb..9c75fc7 100644 --- a/src/main/java/com/ebay/bsonpatch/JsonPointer.java +++ b/src/main/java/com/ebay/bsonpatch/JsonPointer.java @@ -1,14 +1,16 @@ package com.ebay.bsonpatch; +import org.bson.BsonValue; + +import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.bson.BsonValue; - /** * Implements RFC 6901 (JSON Pointer) * @@ -38,9 +40,11 @@ * * @since 0.4.8 */ -class JsonPointer { +public class JsonPointer implements Serializable { private final RefToken[] tokens; + private static final long serialVersionUID = 7876822196894534620L; + /** A JSON pointer representing the root node of a JSON document */ public final static JsonPointer ROOT = new JsonPointer(new RefToken[] {}); @@ -82,8 +86,12 @@ public static JsonPointer parse(String path) throws IllegalArgumentException { // Escape sequences case '~': switch (path.charAt(++i)) { - case '0': reftoken.append('~'); break; - case '1': reftoken.append('/'); break; + case '0': + case '1': + case '2': + reftoken.append('~'); + reftoken.append(path.charAt(i)); + break; default: throw new IllegalArgumentException("Invalid escape sequence ~" + path.charAt(i) + " at index " + i); } @@ -91,7 +99,7 @@ public static JsonPointer parse(String path) throws IllegalArgumentException { // New reftoken case '/': - result.add(new RefToken(reftoken.toString())); + result.add(RefToken.parse(reftoken.toString())); reftoken.setLength(0); break; @@ -124,7 +132,7 @@ public boolean isRoot() { */ JsonPointer append(String field) { RefToken[] newTokens = Arrays.copyOf(tokens, tokens.length + 1); - newTokens[tokens.length] = new RefToken(field); + newTokens[tokens.length] = new RefToken(field, null, null); return new JsonPointer(newTokens); } @@ -135,7 +143,9 @@ JsonPointer append(String field) { * @return The new {@link JsonPointer} instance. */ JsonPointer append(int index) { - return append(Integer.toString(index)); + RefToken[] newTokens = Arrays.copyOf(tokens, tokens.length + 1); + newTokens[tokens.length] = new RefToken(Integer.toString(index), index, null); + return new JsonPointer(newTokens); } /** Returns the number of reference tokens comprising this instance. */ @@ -226,11 +236,27 @@ public BsonValue evaluate(final BsonValue document) throws JsonPointerEvaluation final RefToken token = tokens[idx]; if (current.isArray()) { - if (!token.isArrayIndex()) + if (token.isArrayIndex()) { + if (token.getIndex() == LAST_INDEX || token.getIndex() >= current.asArray().size()) + error(idx, "Array index " + token + " is out of bounds", document); + current = current.asArray().get(token.getIndex()); + } else if (token.isArrayKeyRef()) { + KeyRef keyRef = token.getKeyRef(); + BsonValue foundArrayNode = null; + for (int arrayIdx = 0; arrayIdx < current.asArray().size(); ++arrayIdx) { + BsonValue arrayNode = current.asArray().get(arrayIdx); + if (matches(keyRef, arrayNode)) { + foundArrayNode = arrayNode; + break; + } + } + if (foundArrayNode == null) { + error(idx, "Array has no matching object for key reference " + token, document); + } + current = foundArrayNode; + } else { error(idx, "Can't reference field \"" + token.getField() + "\" on array", document); - if (token.getIndex() == LAST_INDEX || token.getIndex() >= current.asArray().size()) - error(idx, "Array index " + token.toString() + " is out of bounds", document); - current = current.asArray().get(token.getIndex()); + } } else if (current.isDocument()) { if (!current.asDocument().containsKey(token.getField())) @@ -244,6 +270,20 @@ else if (current.isDocument()) { return current; } + private boolean matches(KeyRef keyRef, BsonValue arrayNode) { + boolean matches = false; + if (arrayNode.asDocument().containsKey(keyRef.key)) { + BsonValue valueNode = arrayNode.asDocument().get(keyRef.key); + if (valueNode.isString()) { + matches = Objects.equals(keyRef.value, valueNode.asString().getValue()); + } else if (valueNode.isNumber() || valueNode.isBoolean()) { + matches = Objects.equals(keyRef.value, valueNode.toString()); + } + } + return matches; + } + + @Override public boolean equals(Object o) { if (this == o) return true; @@ -261,62 +301,103 @@ public int hashCode() { } /** Represents a single JSON Pointer reference token. */ - static class RefToken { - private String decodedToken; - transient private Integer index = null; + static class RefToken implements Serializable + { + private final String decodedToken; + private final Integer index; + private final KeyRef keyRef; - public RefToken(String decodedToken) { + private static final long serialVersionUID = -8672427347472605093L; + + private RefToken(String decodedToken, Integer arrayIndex, KeyRef arrayKeyRef) { if (decodedToken == null) throw new IllegalArgumentException("Token can't be null"); this.decodedToken = decodedToken; + this.index = arrayIndex; + this.keyRef = arrayKeyRef; } private static final Pattern DECODED_TILDA_PATTERN = Pattern.compile("~0"); private static final Pattern DECODED_SLASH_PATTERN = Pattern.compile("~1"); + private static final Pattern DECODED_EQUALS_PATTERN = Pattern.compile("~2"); private static String decodePath(Object object) { String path = object.toString(); // see http://tools.ietf.org/html/rfc6901#section-4 path = DECODED_SLASH_PATTERN.matcher(path).replaceAll("/"); - return DECODED_TILDA_PATTERN.matcher(path).replaceAll("~"); + path = DECODED_TILDA_PATTERN.matcher(path).replaceAll("~"); + return DECODED_EQUALS_PATTERN.matcher(path).replaceAll("="); } private static final Pattern ENCODED_TILDA_PATTERN = Pattern.compile("~"); private static final Pattern ENCODED_SLASH_PATTERN = Pattern.compile("/"); + private static final Pattern ENCODED_EQUALS_PATTERN = Pattern.compile("="); private static String encodePath(Object object) { String path = object.toString(); // see http://tools.ietf.org/html/rfc6901#section-4 path = ENCODED_TILDA_PATTERN.matcher(path).replaceAll("~0"); - return ENCODED_SLASH_PATTERN.matcher(path).replaceAll("~1"); + path = ENCODED_SLASH_PATTERN.matcher(path).replaceAll("~1"); + return ENCODED_EQUALS_PATTERN.matcher(path).replaceAll("~2"); } private static final Pattern VALID_ARRAY_IND = Pattern.compile("-|0|(?:[1-9][0-9]*)"); + private static final Pattern VALID_ARRAY_KEY_REF = Pattern.compile("([^=]+)=([^=]+)"); + public static RefToken parse(String rawToken) { if (rawToken == null) throw new IllegalArgumentException("Token can't be null"); - return new RefToken(decodePath(rawToken)); + + Integer index = null; + Matcher indexMatcher = VALID_ARRAY_IND.matcher(rawToken); + if (indexMatcher.matches()) { + if (indexMatcher.group().equals("-")) { + index = LAST_INDEX; + } else { + try { + int validInt = Integer.parseInt(indexMatcher.group()); + index = validInt; + } catch (NumberFormatException ignore) {} + } + } + + KeyRef keyRef = null; + Matcher arrayKeyRefMatcher = VALID_ARRAY_KEY_REF.matcher(rawToken); + if (arrayKeyRefMatcher.matches()) { + keyRef = new KeyRef( + decodePath(arrayKeyRefMatcher.group(1)), + decodePath(arrayKeyRefMatcher.group(2)) + ); + } + return new RefToken(decodePath(rawToken), index, keyRef); } public boolean isArrayIndex() { - if (index != null) return true; - Matcher matcher = VALID_ARRAY_IND.matcher(decodedToken); - if (matcher.matches()) { - index = matcher.group().equals("-") ? LAST_INDEX : Integer.parseInt(matcher.group()); - return true; - } - return false; + return index != null; + } + + public boolean isArrayKeyRef() { + return keyRef != null; } public int getIndex() { - if (!isArrayIndex()) throw new IllegalStateException("Object operation on array target"); + if (!isArrayIndex()) throw new IllegalStateException("Object operation on array index target"); return index; } + public KeyRef getKeyRef() { + if (!isArrayKeyRef()) throw new IllegalStateException("Object operation on array key ref target"); + return keyRef; + } + public String getField() { return decodedToken; } @Override public String toString() { - return encodePath(decodedToken); + if (isArrayKeyRef()) { + return encodePath(keyRef.key) + "=" + encodePath(keyRef.value); + } else { + return encodePath(decodedToken); + } } @Override @@ -335,6 +416,34 @@ public int hashCode() { } } + + static class KeyRef implements Serializable { + private String key; + private String value; + + private static final long serialVersionUID = 6558265555055471373L; + + public KeyRef(String key, String value) { + this.key = key; + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + KeyRef keyRef = (KeyRef) o; + + return Objects.equals(key, keyRef.key) && Objects.equals(value, keyRef.value); + } + + @Override + public int hashCode() { + return Objects.hash(key, value); + } + } + /** * Represents an array index pointing past the end of the array. * diff --git a/src/main/java/com/ebay/bsonpatch/Operation.java b/src/main/java/com/ebay/bsonpatch/Operation.java index 63292ed..e870cb2 100644 --- a/src/main/java/com/ebay/bsonpatch/Operation.java +++ b/src/main/java/com/ebay/bsonpatch/Operation.java @@ -23,7 +23,7 @@ import java.util.HashMap; import java.util.Map; -enum Operation { +public enum Operation { ADD("add"), REMOVE("remove"), REPLACE("replace"), diff --git a/src/test/java/com/ebay/bsonpatch/AbstractTest.java b/src/test/java/com/ebay/bsonpatch/AbstractTest.java index 29c041d..e94b83d 100644 --- a/src/test/java/com/ebay/bsonpatch/AbstractTest.java +++ b/src/test/java/com/ebay/bsonpatch/AbstractTest.java @@ -19,15 +19,6 @@ package com.ebay.bsonpatch; -import static org.hamcrest.core.IsInstanceOf.instanceOf; -import static org.hamcrest.core.StringContains.containsString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import java.io.PrintWriter; -import java.io.StringWriter; - import org.apache.commons.io.output.StringBuilderWriter; import org.bson.BsonArray; import org.bson.BsonDocument; @@ -38,6 +29,15 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameter; +import java.io.PrintWriter; +import java.io.StringWriter; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsInstanceOf.instanceOf; +import static org.hamcrest.core.StringContains.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + @RunWith(Parameterized.class) public abstract class AbstractTest { @@ -51,15 +51,24 @@ protected boolean matchOnErrors() { } @Test - public void test() throws Exception { + public void testApply() throws Exception { if (p.isOperation()) { - testOperation(); + testOperation(false); + } else { + testError(false); + } + } + + @Test + public void testApplyInPlace() throws Exception { + if (p.isOperation() && p.isApplyInPlaceSupported()) { + testOperation(true); } else { - testError(); + testError(true); } } - private void testOperation() throws Exception { + private void testOperation(boolean inPlace) throws Exception { BsonDocument node = p.getNode(); BsonValue doc = node.get("node"); @@ -67,7 +76,13 @@ private void testOperation() throws Exception { BsonArray patch = node.getArray("op"); String message = node.containsKey("message") ? node.getString("message").getValue() : ""; - BsonValue result = BsonPatch.apply(patch, doc); + BsonValue result; + if (inPlace) { + result = CopyingApplyProcessor.deepCopy(doc); + BsonPatch.applyInPlace(patch, result); + } else { + result = BsonPatch.apply(patch, doc); + } String failMessage = "The following test failed: \n" + "message: " + message + '\n' + "at: " + p.getSourceFile(); @@ -97,7 +112,7 @@ private String errorMessage(String header, Exception e) { return res.toString(); } - private void testError() throws ClassNotFoundException { + private void testError(boolean inPlace) throws ClassNotFoundException { BsonDocument node = p.getNode(); BsonValue first = node.get("node"); BsonArray patch = node.getArray("op"); @@ -106,8 +121,12 @@ private void testError() throws ClassNotFoundException { node.containsKey("type") ? exceptionType(node.getString("type").getValue()) : BsonPatchApplicationException.class; try { - BsonPatch.apply(patch, first); - + if (inPlace) { + BsonValue target = CopyingApplyProcessor.deepCopy(first); + BsonPatch.applyInPlace(patch, target); + } else { + BsonPatch.apply(patch, first); + } fail(errorMessage("Failure expected: " + message)); } catch (Exception e) { if (matchOnErrors()) { @@ -118,7 +137,7 @@ private void testError() throws ClassNotFoundException { errorMessage("Operation failed but with wrong exception type", e), e, instanceOf(type)); - if (message != null) { + if (!message.isEmpty()) { assertThat( errorMessage("Operation failed but with wrong message", e), e.toString(), diff --git a/src/test/java/com/ebay/bsonpatch/AddOperationTest.java b/src/test/java/com/ebay/bsonpatch/AddOperationTest.java index a992121..60f84bf 100644 --- a/src/test/java/com/ebay/bsonpatch/AddOperationTest.java +++ b/src/test/java/com/ebay/bsonpatch/AddOperationTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized.Parameters; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized.Parameters; - public class AddOperationTest extends AbstractTest { @Parameters diff --git a/src/test/java/com/ebay/bsonpatch/ApiTest.java b/src/test/java/com/ebay/bsonpatch/ApiTest.java index 193901c..6939c07 100644 --- a/src/test/java/com/ebay/bsonpatch/ApiTest.java +++ b/src/test/java/com/ebay/bsonpatch/ApiTest.java @@ -19,16 +19,16 @@ package com.ebay.bsonpatch; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import org.bson.BsonArray; +import org.bson.BsonDocument; +import org.junit.Test; import java.io.IOException; import java.util.EnumSet; -import org.bson.BsonArray; -import org.bson.BsonDocument; -import org.junit.Test; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; public class ApiTest { diff --git a/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java b/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java index cc9057c..f71d4fe 100644 --- a/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java +++ b/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java @@ -19,22 +19,19 @@ package com.ebay.bsonpatch; -import static com.ebay.bsonpatch.CompatibilityFlags.ALLOW_MISSING_TARGET_OBJECT_ON_REPLACE; -import static com.ebay.bsonpatch.CompatibilityFlags.FORBID_REMOVE_MISSING_OBJECT; -import static com.ebay.bsonpatch.CompatibilityFlags.MISSING_VALUES_AS_NULLS; -import static com.ebay.bsonpatch.CompatibilityFlags.REMOVE_NONE_EXISTING_ARRAY_ELEMENT; -import static org.hamcrest.core.IsEqual.equalTo; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.util.EnumSet; - import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonValue; import org.junit.Before; import org.junit.Test; +import java.io.IOException; +import java.util.EnumSet; + +import static com.ebay.bsonpatch.CompatibilityFlags.*; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; + public class CompatibilityTest { BsonArray addNodeWithMissingValue; diff --git a/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java b/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java index 05e82c2..f521dea 100644 --- a/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java +++ b/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized; - public class CopyOperationTest extends AbstractTest { @Parameterized.Parameters diff --git a/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java b/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java index 2a1fafe..d443270 100644 --- a/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java +++ b/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized; - /** * These tests comes from JS JSON-Patch libraries ( * https://github.com/Starcounter-Jack/JSON-Patch/blob/master/test/spec/json-patch-tests/tests.json diff --git a/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java b/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java index 8ecf788..0e9861d 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java +++ b/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java @@ -19,6 +19,12 @@ package com.ebay.bsonpatch; +import org.apache.commons.io.IOUtils; +import org.bson.*; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; @@ -27,16 +33,6 @@ import static org.junit.Assert.assertEquals; -import org.apache.commons.io.IOUtils; -import org.bson.BsonArray; -import org.bson.BsonDocument; -import org.bson.BsonInt32; -import org.bson.BsonString; -import org.bson.BsonValue; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.Test; - public class JsonDiffTest { private static BsonArray jsonNode; diff --git a/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java b/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java index ed0191c..e14c810 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java +++ b/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java @@ -19,19 +19,19 @@ package com.ebay.bsonpatch; -import static org.hamcrest.core.IsEqual.equalTo; - -import java.io.IOException; -import java.io.InputStream; - import org.apache.commons.io.IOUtils; import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonValue; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; +import java.io.IOException; +import java.io.InputStream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.IsEqual.equalTo; + public class JsonDiffTest2 { private static BsonArray jsonNode; @@ -54,7 +54,7 @@ public void testPatchAppliedCleanly() { String message = node.containsKey("message") ? node.getString("message").getValue() : ""; BsonValue secondPrime = BsonPatch.apply(patch, first); - Assert.assertThat(message, secondPrime, equalTo(second)); + assertThat(message, secondPrime, equalTo(second)); } } diff --git a/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java b/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java index c887374..ff1bc59 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java +++ b/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java @@ -1,16 +1,11 @@ package com.ebay.bsonpatch; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.bson.*; +import org.junit.Test; import java.io.IOException; -import org.bson.BsonArray; -import org.bson.BsonInt32; -import org.bson.BsonString; -import org.bson.BsonValue; -import org.junit.Test; +import static org.junit.Assert.*; public class JsonPointerTest { @@ -33,7 +28,7 @@ public void parsesSingleSlashAsFieldReference() { } @Test - public void parsesArrayIndirection() { + public void parsesArrayIndexIndirection() { JsonPointer parsed = JsonPointer.parse("/0"); assertFalse(parsed.isRoot()); assertEquals(1, parsed.size()); @@ -41,6 +36,15 @@ public void parsesArrayIndirection() { assertEquals(0, parsed.get(0).getIndex()); } + @Test + public void parsesArrayKeyRefIndirection() { + JsonPointer parsed = JsonPointer.parse("/id=ID_1"); + assertFalse(parsed.isRoot()); + assertEquals(1, parsed.size()); + assertTrue(parsed.get(0).isArrayKeyRef()); + assertEquals(new JsonPointer.KeyRef("id", "ID_1"), parsed.get(0).getKeyRef()); + } + @Test public void parsesArrayTailIndirection() { JsonPointer parsed = JsonPointer.parse("/-"); @@ -99,9 +103,9 @@ public void parsesMultipleObjectIndirections() { @Test public void parsesMixedIndirections() { - JsonPointer parsed = JsonPointer.parse("/0/a/1/b"); + JsonPointer parsed = JsonPointer.parse("/0/a/1/b/id=2/c"); assertFalse(parsed.isRoot()); - assertEquals(4, parsed.size()); + assertEquals(6, parsed.size()); assertTrue(parsed.get(0).isArrayIndex()); assertEquals(0, parsed.get(0).getIndex()); assertFalse(parsed.get(1).isArrayIndex()); @@ -110,6 +114,12 @@ public void parsesMixedIndirections() { assertEquals(1, parsed.get(2).getIndex()); assertFalse(parsed.get(3).isArrayIndex()); assertEquals("b", parsed.get(3).getField()); + assertFalse(parsed.get(4).isArrayIndex()); + assertTrue(parsed.get(4).isArrayKeyRef()); + assertEquals(new JsonPointer.KeyRef("id", "2"), parsed.get(4).getKeyRef()); + assertFalse(parsed.get(5).isArrayIndex()); + assertFalse(parsed.get(5).isArrayKeyRef()); + assertEquals("c", parsed.get(5).getField()); } @Test @@ -130,6 +140,15 @@ public void parsesEscapedForwardSlash() { assertEquals("/", parsed.get(0).getField()); } + @Test + public void parsesEscapedEqualsSign() { + JsonPointer parsed = JsonPointer.parse("/~2"); + assertFalse(parsed.isRoot()); + assertEquals(1, parsed.size()); + assertFalse(parsed.get(0).isArrayIndex()); + assertEquals("=", parsed.get(0).getField()); + } + // Parsing error conditions -- @Test(expected = IllegalArgumentException.class) @@ -139,7 +158,7 @@ public void throwsOnMissingLeadingSlash() { @Test(expected = IllegalArgumentException.class) public void throwsOnInvalidEscapedSequence1() { - JsonPointer.parse("/~2"); + JsonPointer.parse("/~3"); } @Test(expected = IllegalArgumentException.class) @@ -169,6 +188,27 @@ public void evaluatesAccordingToRFC6901() throws IOException, JsonPointerEvaluat assertEquals(new BsonInt32(8), JsonPointer.parse("/m~0n").evaluate(testData)); } + @Test + public void evaluatesWithKeyReferences() throws IOException, JsonPointerEvaluationException { + BsonValue data = TestUtils.loadResourceAsBsonValue("/testdata/json-pointer-key-refs.json"); + BsonValue testData = data.asDocument().get("testData"); + + assertEquals(BsonDocument.parse("{\"id\": \"ID_1\",\"some\": \"data_1\"}"), JsonPointer.parse("/objArray/id=ID_1").evaluate(testData)); + assertEquals(new BsonString("data_1"), JsonPointer.parse("/objArray/id=ID_1/some").evaluate(testData)); + assertEquals(new BsonString("data_2"), JsonPointer.parse("/objArray/id=ID_2/some").evaluate(testData)); + assertEquals(new BsonString("some_more"), JsonPointer.parse("/objArray/id=ID_2/and").evaluate(testData)); + assertEquals(new BsonInt32(7), JsonPointer.parse("/objArray/id=ID_2/num").evaluate(testData)); + assertEquals(new BsonString("data_2"), JsonPointer.parse("/objArray/and=some_more/some").evaluate(testData)); + assertEquals(new BsonString("data_3"), JsonPointer.parse("/objArray/id=ID_3/some").evaluate(testData)); + assertEquals(new BsonString("data_4"), JsonPointer.parse("/objArray/id=ID_4/some").evaluate(testData)); + assertEquals(new BsonString("data_4"), JsonPointer.parse("/objArray/3/some").evaluate(testData)); + + assertThrows(JsonPointerEvaluationException.class, () -> JsonPointer.parse("/objArray/id=ID_5").evaluate(testData)); + assertThrows(JsonPointerEvaluationException.class, () -> JsonPointer.parse("/objArray/ref=REF").evaluate(testData)); + assertThrows(JsonPointerEvaluationException.class, () -> JsonPointer.parse("/objArray/4").evaluate(testData)); + } + + // Utility methods -- @Test @@ -189,5 +229,7 @@ public void symmetricalInParsingAndRendering() { assertEquals("/k\"l", JsonPointer.parse("/k\"l").toString()); assertEquals("/ ", JsonPointer.parse("/ ").toString()); assertEquals("/m~0n", JsonPointer.parse("/m~0n").toString()); + assertEquals("/m=n", JsonPointer.parse("/m=n").toString()); + assertEquals("/m~2n", JsonPointer.parse("/m~2n").toString()); } } diff --git a/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java b/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java index 96c2a82..4b71c79 100644 --- a/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java +++ b/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java @@ -19,18 +19,18 @@ package com.ebay.bsonpatch; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; - -import java.io.IOException; -import java.util.Collection; - import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonValue; import org.junit.Test; import org.junit.runners.Parameterized; +import java.io.IOException; +import java.util.Collection; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; + public class MoveOperationTest extends AbstractTest { @Parameterized.Parameters diff --git a/src/test/java/com/ebay/bsonpatch/PatchTestCase.java b/src/test/java/com/ebay/bsonpatch/PatchTestCase.java index 81a96a2..44d4e8e 100644 --- a/src/test/java/com/ebay/bsonpatch/PatchTestCase.java +++ b/src/test/java/com/ebay/bsonpatch/PatchTestCase.java @@ -19,14 +19,14 @@ package com.ebay.bsonpatch; +import org.bson.BsonDocument; +import org.bson.BsonValue; + import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import org.bson.BsonDocument; -import org.bson.BsonValue; - public class PatchTestCase { private final boolean operation; @@ -73,4 +73,9 @@ private static boolean isEnabled(BsonValue node) { BsonValue disabled = node.asDocument().get("disabled"); return (disabled == null || !disabled.asBoolean().getValue()); } + + public boolean isApplyInPlaceSupported() { + BsonValue allowInPlace = node.get("allowInPlace"); + return (allowInPlace == null || allowInPlace.asBoolean().getValue()); + } } diff --git a/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java b/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java index 622846d..ecbcf28 100644 --- a/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java +++ b/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java @@ -5,10 +5,10 @@ import org.bson.BsonValue; import org.junit.Test; -import static org.junit.Assert.assertEquals; - import java.io.IOException; +import static org.junit.Assert.assertEquals; + public class RFC6901Tests { @Test diff --git a/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java b/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java index 7b8a4e6..8abc95f 100644 --- a/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java +++ b/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized; - public class RemoveOperationTest extends AbstractTest { @Parameterized.Parameters diff --git a/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java b/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java index 516745b..a7da691 100644 --- a/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java +++ b/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized; - public class ReplaceOperationTest extends AbstractTest { @Parameterized.Parameters diff --git a/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java b/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java index 1109931..dc6c51b 100644 --- a/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java +++ b/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized; - public class Rfc6902SamplesTest extends AbstractTest { @Parameterized.Parameters diff --git a/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java b/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java index 6237a3a..d6cc2c4 100644 --- a/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java +++ b/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java @@ -19,15 +19,15 @@ package com.ebay.bsonpatch; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonInt32; import org.bson.BsonString; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + public class TestDataGenerator { private static Random random = new Random(); private static List name = Arrays.asList("summers", "winters", "autumn", "spring", "rainy"); diff --git a/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java b/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java index c273b3e..9f07826 100644 --- a/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java +++ b/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java @@ -1,15 +1,15 @@ package com.ebay.bsonpatch; -import java.io.IOException; -import java.util.EnumSet; - -import static org.junit.Assert.*; - import org.bson.BsonArray; import org.bson.BsonDocument; import org.bson.BsonValue; import org.junit.Test; +import java.io.IOException; +import java.util.EnumSet; + +import static org.junit.Assert.assertEquals; + public class TestNodesEmissionTest { private static EnumSet flags; diff --git a/src/test/java/com/ebay/bsonpatch/TestOperationTest.java b/src/test/java/com/ebay/bsonpatch/TestOperationTest.java index f5c0648..796e1f7 100644 --- a/src/test/java/com/ebay/bsonpatch/TestOperationTest.java +++ b/src/test/java/com/ebay/bsonpatch/TestOperationTest.java @@ -19,11 +19,11 @@ package com.ebay.bsonpatch; +import org.junit.runners.Parameterized; + import java.io.IOException; import java.util.Collection; -import org.junit.runners.Parameterized; - public class TestOperationTest extends AbstractTest { @Parameterized.Parameters diff --git a/src/test/java/com/ebay/bsonpatch/TestUtils.java b/src/test/java/com/ebay/bsonpatch/TestUtils.java index 9dbda3e..4b8c5e6 100644 --- a/src/test/java/com/ebay/bsonpatch/TestUtils.java +++ b/src/test/java/com/ebay/bsonpatch/TestUtils.java @@ -1,12 +1,12 @@ package com.ebay.bsonpatch; -import java.io.IOException; -import java.io.InputStream; - import org.apache.commons.io.IOUtils; import org.bson.BsonDocument; import org.bson.BsonValue; +import java.io.IOException; +import java.io.InputStream; + public class TestUtils { private TestUtils() { @@ -21,4 +21,32 @@ public static String loadFromResources(String path) throws IOException { InputStream resourceAsStream = PatchTestCase.class.getResourceAsStream(path); return IOUtils.toString(resourceAsStream, "UTF-8"); } + + public static String stripJsonComments(String s) { + StringBuilder out = new StringBuilder(); + boolean inStr = false, esc = false, inLine = false, inBlock = false; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i), n = (i + 1 < s.length()) ? s.charAt(i + 1) : '\0'; + if (inLine) { + if (c == '\n') { inLine = false; out.append(c); } + continue; + } + if (inBlock) { + if (c == '*' && n == '/') { inBlock = false; i++; } + continue; + } + if (inStr) { + out.append(c); + if (!esc && c == '\\') { esc = true; } + else if (esc) { esc = false; } + else if (c == '"') { inStr = false; } + continue; + } + if (c == '"') { inStr = true; out.append(c); continue; } + if (c == '/' && n == '/') { inLine = true; i++; continue; } + if (c == '/' && n == '*') { inBlock = true; i++; continue; } + out.append(c); + } + return out.toString(); + } } \ No newline at end of file diff --git a/src/test/java/com/ebay/bsonpatch/ValidationTest.java b/src/test/java/com/ebay/bsonpatch/ValidationTest.java new file mode 100644 index 0000000..f760d51 --- /dev/null +++ b/src/test/java/com/ebay/bsonpatch/ValidationTest.java @@ -0,0 +1,40 @@ +package com.ebay.bsonpatch; + +import org.bson.BsonArray; +import org.bson.BsonValue; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ValidationTest { + + @ParameterizedTest + @MethodSource("argsForValidationTest") + public void testValidation(BsonArray patch) { + assertThrows( + InvalidBsonPatchException.class, + () -> BsonPatch.validate(patch) + ); + } + + public static Stream argsForValidationTest() throws IOException { + BsonValue patches = BsonArray.parse( + TestUtils.stripJsonComments( + TestUtils.loadFromResources("/testdata/invalid-patches.json"))); + + List args = new ArrayList<>(); + + for (BsonValue patch : patches.asArray()) { + args.add(Arguments.of(patch)); + } + + return args.stream(); + } +} \ No newline at end of file diff --git a/src/test/resources/testdata/invalid-patches.json b/src/test/resources/testdata/invalid-patches.json new file mode 100644 index 0000000..bfdad2f --- /dev/null +++ b/src/test/resources/testdata/invalid-patches.json @@ -0,0 +1,37 @@ +[ + // no operation + [{"path": "/field1", "value": {"id":123}}], + + // TEST operation with no path + [{"op": "test", "value": {"id":123}}], + + // TEST operation with no value + [{"op": "test", "path": "/field1"}], + + // TEST operation with non-text 'path' attribute + [{"op": "test", "path": 1, "value": {"id":123}}], + + // ADD operation with no 'path' attribute + [{"op": "add", "value": "b"}], + + // ADD operation with non-text 'path' attribute + [{"op": "add", "path": 123, "value": "b"}], + + // ADD operation with no 'value' attribute + [{"op": "add", "path": "/field1/a"}], + + // REPLACE operation patch with no 'value' attribute + [{"op": "replace", "path": "/field1/a"}], + + // MOVE operation with no 'from' attribute + [{"op": "move", "path": "/field1/a"}], + + // COPY operation with no 'from' attribute + [{"op": "move", "path": "/field1/a"}], + + // MOVE operation with no non-text 'from' attribute + [{"op": "move", "path": "/field1/a", "from": 123}], + + // COPY operation with no non-text 'from' attribute + [{"op": "copy", "path": "/field1/a", "from": 123}] +] \ No newline at end of file diff --git a/src/test/resources/testdata/js-libs-samples.json b/src/test/resources/testdata/js-libs-samples.json index 3a56ea0..2b71e35 100644 --- a/src/test/resources/testdata/js-libs-samples.json +++ b/src/test/resources/testdata/js-libs-samples.json @@ -75,12 +75,14 @@ { "message": "replacing the root of the document is possible with add", "node": {"foo": "bar"}, "op": [{"op": "add", "path": "", "value": {"baz": "qux"}}], - "expected": {"baz":"qux"}}, + "expected": {"baz":"qux"}, + "allowInPlace": false }, { "message": "replacing the root of the document is possible with add", "node": {"foo": "bar"}, "op": [{"op": "add", "path": "", "value": ["baz", "qux"]}], - "expected": ["baz", "qux"]}, + "expected": ["baz", "qux"], + "allowInPlace": false }, { "message": "empty list, empty docs", "node": {}, @@ -235,7 +237,8 @@ { "message": "replace whole document", "node": {"foo": "bar"}, "op": [{"op": "replace", "path": "", "value": {"baz": "qux"}}], - "expected": {"baz": "qux"} }, + "expected": {"baz": "qux"}, + "allowInPlace": false }, { "node": {"foo": null}, "op": [{"op": "replace", "path": "/foo", "value": "truthy"}], diff --git a/src/test/resources/testdata/json-pointer-key-refs.json b/src/test/resources/testdata/json-pointer-key-refs.json new file mode 100644 index 0000000..0ef7338 --- /dev/null +++ b/src/test/resources/testdata/json-pointer-key-refs.json @@ -0,0 +1,26 @@ +{ + "testData": { + "objArray": [ + { + "id": "ID_1", + "some": "data_1" + }, + { + "id": "ID_2", + "some": "data_2", + "and": "some_more", + "num": 7 + }, + { + "id": "ID_3", + "some": "data_3", + "and": "some_more" + }, + { + "id": "ID_4", + "some": "data_4", + "and": "some_more" + } + ] + } +} \ No newline at end of file diff --git a/src/test/resources/testdata/replace.json b/src/test/resources/testdata/replace.json index 3865d52..9e31520 100644 --- a/src/test/resources/testdata/replace.json +++ b/src/test/resources/testdata/replace.json @@ -21,7 +21,8 @@ { "op": [{ "op": "replace", "path": "", "value": false }], "node": { "x": { "a": "b", "y": {} } }, - "expected": false + "expected": false, + "allowInPlace": false }, { "op": [{ "op": "replace", "path": "/x/y", "value": "hello" }], From d9aa230deed691c3efa8d136fa59ecc4415580fd Mon Sep 17 00:00:00 2001 From: Dan Douglas Date: Thu, 28 Aug 2025 17:49:31 -0700 Subject: [PATCH 2/3] repackage in new github org --- pom.xml | 13 ++++++------- .../{com/ebay => io/github}/bsonpatch/BsonDiff.java | 2 +- .../ebay => io/github}/bsonpatch/BsonPatch.java | 4 ++-- .../bsonpatch/BsonPatchApplicationException.java | 2 +- .../github}/bsonpatch/BsonPatchProcessor.java | 2 +- .../github}/bsonpatch/CompatibilityFlags.java | 2 +- .../ebay => io/github}/bsonpatch/Constants.java | 2 +- .../github}/bsonpatch/CopyingApplyProcessor.java | 2 +- .../{com/ebay => io/github}/bsonpatch/Diff.java | 2 +- .../ebay => io/github}/bsonpatch/DiffFlags.java | 2 +- .../github}/bsonpatch/InPlaceApplyProcessor.java | 2 +- .../ebay => io/github}/bsonpatch/InternalUtils.java | 2 +- .../bsonpatch/InvalidBsonPatchException.java | 2 +- .../ebay => io/github}/bsonpatch/JsonPointer.java | 2 +- .../bsonpatch/JsonPointerEvaluationException.java | 2 +- .../ebay => io/github}/bsonpatch/NoopProcessor.java | 2 +- .../ebay => io/github}/bsonpatch/Operation.java | 2 +- .../ebay => io/github}/bsonpatch/AbstractTest.java | 4 ++-- .../github}/bsonpatch/AddOperationTest.java | 2 +- .../{com/ebay => io/github}/bsonpatch/ApiTest.java | 2 +- .../github}/bsonpatch/CompatibilityTest.java | 4 ++-- .../github}/bsonpatch/CopyOperationTest.java | 2 +- .../github}/bsonpatch/JsLibSamplesTest.java | 2 +- .../ebay => io/github}/bsonpatch/JsonDiffTest.java | 2 +- .../ebay => io/github}/bsonpatch/JsonDiffTest2.java | 2 +- .../github}/bsonpatch/JsonPointerTest.java | 2 +- .../github}/bsonpatch/JsonSplitReplaceOpTest.java | 2 +- .../github}/bsonpatch/MoveOperationTest.java | 2 +- .../ebay => io/github}/bsonpatch/PatchTestCase.java | 2 +- .../ebay => io/github}/bsonpatch/RFC6901Tests.java | 2 +- .../github}/bsonpatch/RemoveOperationTest.java | 2 +- .../github}/bsonpatch/ReplaceOperationTest.java | 2 +- .../github}/bsonpatch/Rfc6902SamplesTest.java | 2 +- .../github}/bsonpatch/TestDataGenerator.java | 2 +- .../github}/bsonpatch/TestNodesEmissionTest.java | 2 +- .../github}/bsonpatch/TestOperationTest.java | 2 +- .../ebay => io/github}/bsonpatch/TestUtils.java | 2 +- .../github}/bsonpatch/ValidationTest.java | 2 +- 38 files changed, 46 insertions(+), 47 deletions(-) rename src/main/java/{com/ebay => io/github}/bsonpatch/BsonDiff.java (99%) rename src/main/java/{com/ebay => io/github}/bsonpatch/BsonPatch.java (98%) rename src/main/java/{com/ebay => io/github}/bsonpatch/BsonPatchApplicationException.java (98%) rename src/main/java/{com/ebay => io/github}/bsonpatch/BsonPatchProcessor.java (97%) rename src/main/java/{com/ebay => io/github}/bsonpatch/CompatibilityFlags.java (97%) rename src/main/java/{com/ebay => io/github}/bsonpatch/Constants.java (97%) rename src/main/java/{com/ebay => io/github}/bsonpatch/CopyingApplyProcessor.java (98%) rename src/main/java/{com/ebay => io/github}/bsonpatch/Diff.java (98%) rename src/main/java/{com/ebay => io/github}/bsonpatch/DiffFlags.java (99%) rename src/main/java/{com/ebay => io/github}/bsonpatch/InPlaceApplyProcessor.java (99%) rename src/main/java/{com/ebay => io/github}/bsonpatch/InternalUtils.java (98%) rename src/main/java/{com/ebay => io/github}/bsonpatch/InvalidBsonPatchException.java (97%) rename src/main/java/{com/ebay => io/github}/bsonpatch/JsonPointer.java (99%) rename src/main/java/{com/ebay => io/github}/bsonpatch/JsonPointerEvaluationException.java (94%) rename src/main/java/{com/ebay => io/github}/bsonpatch/NoopProcessor.java (98%) rename src/main/java/{com/ebay => io/github}/bsonpatch/Operation.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/AbstractTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/AddOperationTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/ApiTest.java (99%) rename src/test/java/{com/ebay => io/github}/bsonpatch/CompatibilityTest.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/CopyOperationTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/JsLibSamplesTest.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/JsonDiffTest.java (99%) rename src/test/java/{com/ebay => io/github}/bsonpatch/JsonDiffTest2.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/JsonPointerTest.java (99%) rename src/test/java/{com/ebay => io/github}/bsonpatch/JsonSplitReplaceOpTest.java (99%) rename src/test/java/{com/ebay => io/github}/bsonpatch/MoveOperationTest.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/PatchTestCase.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/RFC6901Tests.java (95%) rename src/test/java/{com/ebay => io/github}/bsonpatch/RemoveOperationTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/ReplaceOperationTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/Rfc6902SamplesTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/TestDataGenerator.java (99%) rename src/test/java/{com/ebay => io/github}/bsonpatch/TestNodesEmissionTest.java (99%) rename src/test/java/{com/ebay => io/github}/bsonpatch/TestOperationTest.java (97%) rename src/test/java/{com/ebay => io/github}/bsonpatch/TestUtils.java (98%) rename src/test/java/{com/ebay => io/github}/bsonpatch/ValidationTest.java (97%) diff --git a/pom.xml b/pom.xml index a8ce635..a9001cd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,19 +4,19 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - io.github.dandoug + io.github.bsonpatch bsonpatch 0.5.0-SNAPSHOT jar ${project.groupId}:${project.artifactId} Java Library to find / apply JSON Patches according to RFC 6902 against BsonValues - https://github.com/dandoug/bsonpatch/ + https://github.com/bsonpatch/bsonpatch/ - scm:git:git://github.com/dandoug/bsonpatch.git - scm:git:ssh://github.com:dandoug/bsonpatch.git - https://github.com/dandoug/bsonpatch/tree/master + scm:git:git://github.com/bsonpatch/bsonpatch.git + scm:git:ssh://github.com:bsonpatch/bsonpatch.git + https://github.com/bsonpatch/bsonpatch/tree/master @@ -138,13 +138,12 @@ mongo-java-driver 3.12.14 - org.apache.commons commons-collections4 4.5.0 - test + commons-io commons-io diff --git a/src/main/java/com/ebay/bsonpatch/BsonDiff.java b/src/main/java/io/github/bsonpatch/BsonDiff.java similarity index 99% rename from src/main/java/com/ebay/bsonpatch/BsonDiff.java rename to src/main/java/io/github/bsonpatch/BsonDiff.java index 2a572ce..b20e0da 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonDiff.java +++ b/src/main/java/io/github/bsonpatch/BsonDiff.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.apache.commons.collections4.ListUtils; import org.bson.BsonArray; diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatch.java b/src/main/java/io/github/bsonpatch/BsonPatch.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/BsonPatch.java rename to src/main/java/io/github/bsonpatch/BsonPatch.java index 3cd8328..6d7329b 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonPatch.java +++ b/src/main/java/io/github/bsonpatch/BsonPatch.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonNull; @@ -26,7 +26,7 @@ import java.util.EnumSet; import java.util.Iterator; -import static com.ebay.bsonpatch.InPlaceApplyProcessor.cloneBsonValue; +import static io.github.bsonpatch.InPlaceApplyProcessor.cloneBsonValue; public final class BsonPatch { diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java b/src/main/java/io/github/bsonpatch/BsonPatchApplicationException.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java rename to src/main/java/io/github/bsonpatch/BsonPatchApplicationException.java index 1a0bb6e..60454c1 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonPatchApplicationException.java +++ b/src/main/java/io/github/bsonpatch/BsonPatchApplicationException.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; public class BsonPatchApplicationException extends RuntimeException { private static final long serialVersionUID = 7562538769544371424L; diff --git a/src/main/java/com/ebay/bsonpatch/BsonPatchProcessor.java b/src/main/java/io/github/bsonpatch/BsonPatchProcessor.java similarity index 97% rename from src/main/java/com/ebay/bsonpatch/BsonPatchProcessor.java rename to src/main/java/io/github/bsonpatch/BsonPatchProcessor.java index 1c5c17d..ba0aef8 100644 --- a/src/main/java/com/ebay/bsonpatch/BsonPatchProcessor.java +++ b/src/main/java/io/github/bsonpatch/BsonPatchProcessor.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonValue; diff --git a/src/main/java/com/ebay/bsonpatch/CompatibilityFlags.java b/src/main/java/io/github/bsonpatch/CompatibilityFlags.java similarity index 97% rename from src/main/java/com/ebay/bsonpatch/CompatibilityFlags.java rename to src/main/java/io/github/bsonpatch/CompatibilityFlags.java index 4293ea7..3994fd0 100644 --- a/src/main/java/com/ebay/bsonpatch/CompatibilityFlags.java +++ b/src/main/java/io/github/bsonpatch/CompatibilityFlags.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import java.util.EnumSet; diff --git a/src/main/java/com/ebay/bsonpatch/Constants.java b/src/main/java/io/github/bsonpatch/Constants.java similarity index 97% rename from src/main/java/com/ebay/bsonpatch/Constants.java rename to src/main/java/io/github/bsonpatch/Constants.java index 7ebb358..158a3f0 100644 --- a/src/main/java/com/ebay/bsonpatch/Constants.java +++ b/src/main/java/io/github/bsonpatch/Constants.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; final class Constants { public static final String OP = "op"; diff --git a/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java b/src/main/java/io/github/bsonpatch/CopyingApplyProcessor.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java rename to src/main/java/io/github/bsonpatch/CopyingApplyProcessor.java index faaf3f3..ec25972 100644 --- a/src/main/java/com/ebay/bsonpatch/CopyingApplyProcessor.java +++ b/src/main/java/io/github/bsonpatch/CopyingApplyProcessor.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonBinary; import org.bson.BsonJavaScriptWithScope; diff --git a/src/main/java/com/ebay/bsonpatch/Diff.java b/src/main/java/io/github/bsonpatch/Diff.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/Diff.java rename to src/main/java/io/github/bsonpatch/Diff.java index f798189..3b6350e 100644 --- a/src/main/java/com/ebay/bsonpatch/Diff.java +++ b/src/main/java/io/github/bsonpatch/Diff.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonValue; diff --git a/src/main/java/com/ebay/bsonpatch/DiffFlags.java b/src/main/java/io/github/bsonpatch/DiffFlags.java similarity index 99% rename from src/main/java/com/ebay/bsonpatch/DiffFlags.java rename to src/main/java/io/github/bsonpatch/DiffFlags.java index 6a60301..e065f7f 100644 --- a/src/main/java/com/ebay/bsonpatch/DiffFlags.java +++ b/src/main/java/io/github/bsonpatch/DiffFlags.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import java.util.EnumSet; diff --git a/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java b/src/main/java/io/github/bsonpatch/InPlaceApplyProcessor.java similarity index 99% rename from src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java rename to src/main/java/io/github/bsonpatch/InPlaceApplyProcessor.java index 765117e..0f00cb9 100644 --- a/src/main/java/com/ebay/bsonpatch/InPlaceApplyProcessor.java +++ b/src/main/java/io/github/bsonpatch/InPlaceApplyProcessor.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.*; diff --git a/src/main/java/com/ebay/bsonpatch/InternalUtils.java b/src/main/java/io/github/bsonpatch/InternalUtils.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/InternalUtils.java rename to src/main/java/io/github/bsonpatch/InternalUtils.java index ae1a448..2413d31 100644 --- a/src/main/java/com/ebay/bsonpatch/InternalUtils.java +++ b/src/main/java/io/github/bsonpatch/InternalUtils.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonValue; diff --git a/src/main/java/com/ebay/bsonpatch/InvalidBsonPatchException.java b/src/main/java/io/github/bsonpatch/InvalidBsonPatchException.java similarity index 97% rename from src/main/java/com/ebay/bsonpatch/InvalidBsonPatchException.java rename to src/main/java/io/github/bsonpatch/InvalidBsonPatchException.java index 3a29a5b..e85d196 100644 --- a/src/main/java/com/ebay/bsonpatch/InvalidBsonPatchException.java +++ b/src/main/java/io/github/bsonpatch/InvalidBsonPatchException.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; public class InvalidBsonPatchException extends BsonPatchApplicationException { private static final long serialVersionUID = 1525480895357401013L; diff --git a/src/main/java/com/ebay/bsonpatch/JsonPointer.java b/src/main/java/io/github/bsonpatch/JsonPointer.java similarity index 99% rename from src/main/java/com/ebay/bsonpatch/JsonPointer.java rename to src/main/java/io/github/bsonpatch/JsonPointer.java index 9c75fc7..444c25d 100644 --- a/src/main/java/com/ebay/bsonpatch/JsonPointer.java +++ b/src/main/java/io/github/bsonpatch/JsonPointer.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonValue; diff --git a/src/main/java/com/ebay/bsonpatch/JsonPointerEvaluationException.java b/src/main/java/io/github/bsonpatch/JsonPointerEvaluationException.java similarity index 94% rename from src/main/java/com/ebay/bsonpatch/JsonPointerEvaluationException.java rename to src/main/java/io/github/bsonpatch/JsonPointerEvaluationException.java index 192ee0c..3043ede 100644 --- a/src/main/java/com/ebay/bsonpatch/JsonPointerEvaluationException.java +++ b/src/main/java/io/github/bsonpatch/JsonPointerEvaluationException.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonValue; diff --git a/src/main/java/com/ebay/bsonpatch/NoopProcessor.java b/src/main/java/io/github/bsonpatch/NoopProcessor.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/NoopProcessor.java rename to src/main/java/io/github/bsonpatch/NoopProcessor.java index 71e0acf..38d5093 100644 --- a/src/main/java/com/ebay/bsonpatch/NoopProcessor.java +++ b/src/main/java/io/github/bsonpatch/NoopProcessor.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonValue; diff --git a/src/main/java/com/ebay/bsonpatch/Operation.java b/src/main/java/io/github/bsonpatch/Operation.java similarity index 98% rename from src/main/java/com/ebay/bsonpatch/Operation.java rename to src/main/java/io/github/bsonpatch/Operation.java index e870cb2..354848a 100644 --- a/src/main/java/com/ebay/bsonpatch/Operation.java +++ b/src/main/java/io/github/bsonpatch/Operation.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import java.util.Collections; import java.util.HashMap; diff --git a/src/test/java/com/ebay/bsonpatch/AbstractTest.java b/src/test/java/io/github/bsonpatch/AbstractTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/AbstractTest.java rename to src/test/java/io/github/bsonpatch/AbstractTest.java index e94b83d..4629575 100644 --- a/src/test/java/com/ebay/bsonpatch/AbstractTest.java +++ b/src/test/java/io/github/bsonpatch/AbstractTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.apache.commons.io.output.StringBuilderWriter; import org.bson.BsonArray; @@ -90,7 +90,7 @@ private void testOperation(boolean inPlace) throws Exception { } private Class exceptionType(String type) throws ClassNotFoundException { - return Class.forName(type.contains(".") ? type : "com.ebay.bsonpatch." + type); + return Class.forName(type.contains(".") ? type : "io.github.bsonpatch." + type); } private String errorMessage(String header) { diff --git a/src/test/java/com/ebay/bsonpatch/AddOperationTest.java b/src/test/java/io/github/bsonpatch/AddOperationTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/AddOperationTest.java rename to src/test/java/io/github/bsonpatch/AddOperationTest.java index 60f84bf..e467f9b 100644 --- a/src/test/java/com/ebay/bsonpatch/AddOperationTest.java +++ b/src/test/java/io/github/bsonpatch/AddOperationTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized.Parameters; diff --git a/src/test/java/com/ebay/bsonpatch/ApiTest.java b/src/test/java/io/github/bsonpatch/ApiTest.java similarity index 99% rename from src/test/java/com/ebay/bsonpatch/ApiTest.java rename to src/test/java/io/github/bsonpatch/ApiTest.java index 6939c07..e6678fe 100644 --- a/src/test/java/com/ebay/bsonpatch/ApiTest.java +++ b/src/test/java/io/github/bsonpatch/ApiTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java b/src/test/java/io/github/bsonpatch/CompatibilityTest.java similarity index 98% rename from src/test/java/com/ebay/bsonpatch/CompatibilityTest.java rename to src/test/java/io/github/bsonpatch/CompatibilityTest.java index f71d4fe..23d1644 100644 --- a/src/test/java/com/ebay/bsonpatch/CompatibilityTest.java +++ b/src/test/java/io/github/bsonpatch/CompatibilityTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; @@ -28,7 +28,7 @@ import java.io.IOException; import java.util.EnumSet; -import static com.ebay.bsonpatch.CompatibilityFlags.*; +import static io.github.bsonpatch.CompatibilityFlags.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; diff --git a/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java b/src/test/java/io/github/bsonpatch/CopyOperationTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/CopyOperationTest.java rename to src/test/java/io/github/bsonpatch/CopyOperationTest.java index f521dea..671aee7 100644 --- a/src/test/java/com/ebay/bsonpatch/CopyOperationTest.java +++ b/src/test/java/io/github/bsonpatch/CopyOperationTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized; diff --git a/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java b/src/test/java/io/github/bsonpatch/JsLibSamplesTest.java similarity index 98% rename from src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java rename to src/test/java/io/github/bsonpatch/JsLibSamplesTest.java index d443270..03bf422 100644 --- a/src/test/java/com/ebay/bsonpatch/JsLibSamplesTest.java +++ b/src/test/java/io/github/bsonpatch/JsLibSamplesTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized; diff --git a/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java b/src/test/java/io/github/bsonpatch/JsonDiffTest.java similarity index 99% rename from src/test/java/com/ebay/bsonpatch/JsonDiffTest.java rename to src/test/java/io/github/bsonpatch/JsonDiffTest.java index 0e9861d..e0d7ef6 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonDiffTest.java +++ b/src/test/java/io/github/bsonpatch/JsonDiffTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.apache.commons.io.IOUtils; import org.bson.*; diff --git a/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java b/src/test/java/io/github/bsonpatch/JsonDiffTest2.java similarity index 98% rename from src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java rename to src/test/java/io/github/bsonpatch/JsonDiffTest2.java index e14c810..4f9e748 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonDiffTest2.java +++ b/src/test/java/io/github/bsonpatch/JsonDiffTest2.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.apache.commons.io.IOUtils; import org.bson.BsonArray; diff --git a/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java b/src/test/java/io/github/bsonpatch/JsonPointerTest.java similarity index 99% rename from src/test/java/com/ebay/bsonpatch/JsonPointerTest.java rename to src/test/java/io/github/bsonpatch/JsonPointerTest.java index ff1bc59..fef6152 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonPointerTest.java +++ b/src/test/java/io/github/bsonpatch/JsonPointerTest.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.*; import org.junit.Test; diff --git a/src/test/java/com/ebay/bsonpatch/JsonSplitReplaceOpTest.java b/src/test/java/io/github/bsonpatch/JsonSplitReplaceOpTest.java similarity index 99% rename from src/test/java/com/ebay/bsonpatch/JsonSplitReplaceOpTest.java rename to src/test/java/io/github/bsonpatch/JsonSplitReplaceOpTest.java index 74dc9dc..bb7f773 100644 --- a/src/test/java/com/ebay/bsonpatch/JsonSplitReplaceOpTest.java +++ b/src/test/java/io/github/bsonpatch/JsonSplitReplaceOpTest.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java b/src/test/java/io/github/bsonpatch/MoveOperationTest.java similarity index 98% rename from src/test/java/com/ebay/bsonpatch/MoveOperationTest.java rename to src/test/java/io/github/bsonpatch/MoveOperationTest.java index 4b71c79..43b0fd3 100644 --- a/src/test/java/com/ebay/bsonpatch/MoveOperationTest.java +++ b/src/test/java/io/github/bsonpatch/MoveOperationTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/PatchTestCase.java b/src/test/java/io/github/bsonpatch/PatchTestCase.java similarity index 98% rename from src/test/java/com/ebay/bsonpatch/PatchTestCase.java rename to src/test/java/io/github/bsonpatch/PatchTestCase.java index 44d4e8e..273c0c4 100644 --- a/src/test/java/com/ebay/bsonpatch/PatchTestCase.java +++ b/src/test/java/io/github/bsonpatch/PatchTestCase.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonDocument; import org.bson.BsonValue; diff --git a/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java b/src/test/java/io/github/bsonpatch/RFC6901Tests.java similarity index 95% rename from src/test/java/com/ebay/bsonpatch/RFC6901Tests.java rename to src/test/java/io/github/bsonpatch/RFC6901Tests.java index ecbcf28..7eaa03f 100644 --- a/src/test/java/com/ebay/bsonpatch/RFC6901Tests.java +++ b/src/test/java/io/github/bsonpatch/RFC6901Tests.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java b/src/test/java/io/github/bsonpatch/RemoveOperationTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java rename to src/test/java/io/github/bsonpatch/RemoveOperationTest.java index 8abc95f..46b4509 100644 --- a/src/test/java/com/ebay/bsonpatch/RemoveOperationTest.java +++ b/src/test/java/io/github/bsonpatch/RemoveOperationTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized; diff --git a/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java b/src/test/java/io/github/bsonpatch/ReplaceOperationTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java rename to src/test/java/io/github/bsonpatch/ReplaceOperationTest.java index a7da691..ef4a6ba 100644 --- a/src/test/java/com/ebay/bsonpatch/ReplaceOperationTest.java +++ b/src/test/java/io/github/bsonpatch/ReplaceOperationTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized; diff --git a/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java b/src/test/java/io/github/bsonpatch/Rfc6902SamplesTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java rename to src/test/java/io/github/bsonpatch/Rfc6902SamplesTest.java index dc6c51b..3484520 100644 --- a/src/test/java/com/ebay/bsonpatch/Rfc6902SamplesTest.java +++ b/src/test/java/io/github/bsonpatch/Rfc6902SamplesTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized; diff --git a/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java b/src/test/java/io/github/bsonpatch/TestDataGenerator.java similarity index 99% rename from src/test/java/com/ebay/bsonpatch/TestDataGenerator.java rename to src/test/java/io/github/bsonpatch/TestDataGenerator.java index d6cc2c4..9b44b26 100644 --- a/src/test/java/com/ebay/bsonpatch/TestDataGenerator.java +++ b/src/test/java/io/github/bsonpatch/TestDataGenerator.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java b/src/test/java/io/github/bsonpatch/TestNodesEmissionTest.java similarity index 99% rename from src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java rename to src/test/java/io/github/bsonpatch/TestNodesEmissionTest.java index 9f07826..23e4e69 100644 --- a/src/test/java/com/ebay/bsonpatch/TestNodesEmissionTest.java +++ b/src/test/java/io/github/bsonpatch/TestNodesEmissionTest.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/TestOperationTest.java b/src/test/java/io/github/bsonpatch/TestOperationTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/TestOperationTest.java rename to src/test/java/io/github/bsonpatch/TestOperationTest.java index 796e1f7..a0c3bc7 100644 --- a/src/test/java/com/ebay/bsonpatch/TestOperationTest.java +++ b/src/test/java/io/github/bsonpatch/TestOperationTest.java @@ -17,7 +17,7 @@ * under the License. */ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.junit.runners.Parameterized; diff --git a/src/test/java/com/ebay/bsonpatch/TestUtils.java b/src/test/java/io/github/bsonpatch/TestUtils.java similarity index 98% rename from src/test/java/com/ebay/bsonpatch/TestUtils.java rename to src/test/java/io/github/bsonpatch/TestUtils.java index 4b8c5e6..ee2560e 100644 --- a/src/test/java/com/ebay/bsonpatch/TestUtils.java +++ b/src/test/java/io/github/bsonpatch/TestUtils.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.apache.commons.io.IOUtils; import org.bson.BsonDocument; diff --git a/src/test/java/com/ebay/bsonpatch/ValidationTest.java b/src/test/java/io/github/bsonpatch/ValidationTest.java similarity index 97% rename from src/test/java/com/ebay/bsonpatch/ValidationTest.java rename to src/test/java/io/github/bsonpatch/ValidationTest.java index f760d51..cae9803 100644 --- a/src/test/java/com/ebay/bsonpatch/ValidationTest.java +++ b/src/test/java/io/github/bsonpatch/ValidationTest.java @@ -1,4 +1,4 @@ -package com.ebay.bsonpatch; +package io.github.bsonpatch; import org.bson.BsonArray; import org.bson.BsonValue; From 693faa531871253a73e7de95baecaa198c0ea534 Mon Sep 17 00:00:00 2001 From: Dan Douglas Date: Thu, 28 Aug 2025 18:04:56 -0700 Subject: [PATCH 3/3] add ci workflow --- .github/workflows/ci.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d696af2 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,19 @@ +name: Java CI + +on: + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up JDK 24 + uses: actions/setup-java@v4 + with: + java-version: '24' + distribution: 'zulu' + - name: Build with Maven + run: mvn -B verify \ No newline at end of file