-
Notifications
You must be signed in to change notification settings - Fork 196
Removes jackson-utils dependency. #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
20aa93a
ec7ec41
88d7cb7
829cf10
e7d4138
97a7b55
ed5f746
c86a89d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,16 +19,13 @@ | |
|
|
||
| package com.github.fge.jsonpatch; | ||
|
|
||
| import static com.github.fge.jsonpatch.JacksonUtils.head; | ||
| import com.fasterxml.jackson.annotation.JsonCreator; | ||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import com.fasterxml.jackson.core.JsonPointer; | ||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.node.ArrayNode; | ||
| import com.fasterxml.jackson.databind.node.ObjectNode; | ||
| import com.github.fge.jackson.jsonpointer.JsonPointer; | ||
| import com.github.fge.jackson.jsonpointer.ReferenceToken; | ||
| import com.github.fge.jackson.jsonpointer.TokenResolver; | ||
| import com.google.common.collect.Iterables; | ||
|
|
||
|
|
||
| /** | ||
| * JSON Patch {@code add} operation | ||
|
|
@@ -67,8 +64,9 @@ | |
| public final class AddOperation | ||
| extends PathValueOperation | ||
| { | ||
| private static final ReferenceToken LAST_ARRAY_ELEMENT | ||
| = ReferenceToken.fromRaw("-"); | ||
|
|
||
| private static final JsonPointer EMPTY = JsonPointer.compile(""); | ||
| private static final String LAST_ARRAY_ELEMENT = "-"; | ||
|
|
||
| @JsonCreator | ||
| public AddOperation(@JsonProperty("path") final JsonPointer path, | ||
|
|
@@ -81,14 +79,15 @@ public AddOperation(@JsonProperty("path") final JsonPointer path, | |
| public JsonNode apply(final JsonNode node) | ||
| throws JsonPatchException | ||
| { | ||
| if (path.isEmpty()) | ||
| if (EMPTY.equals(path)) | ||
| return value; | ||
|
|
||
| /* | ||
| * Check the parent node: it must exist and be a container (ie an array | ||
| * or an object) for the add operation to work. | ||
| */ | ||
| final JsonNode parentNode = path.parent().path(node); | ||
| final JsonNode parentNode = node.at(head(path)); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Jackson applies a JSonPointer over a JsonNode and not the inverse as used in jackson-utils. Side note: we have sent a PR to jackson-core to add support for head() method natively. |
||
|
|
||
| if (parentNode.isMissingNode()) | ||
| throw new JsonPatchException(BUNDLE.getMessage( | ||
| "jsonPatch.noSuchParent")); | ||
|
|
@@ -104,10 +103,10 @@ private JsonNode addToArray(final JsonPointer path, final JsonNode node) | |
| throws JsonPatchException | ||
| { | ||
| final JsonNode ret = node.deepCopy(); | ||
| final ArrayNode target = (ArrayNode) path.parent().get(ret); | ||
| final TokenResolver<JsonNode> token = Iterables.getLast(path); | ||
| final ArrayNode target = (ArrayNode)ret.at(head(path)); | ||
| final String token = JacksonUtils.getLast(path); | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Returns the last part of the jsonpointer. Again this operation does not exists directly in Jackson JsonPointer implementation and we have created an implementation for fixing this. |
||
|
|
||
| if (token.getToken().equals(LAST_ARRAY_ELEMENT)) { | ||
| if (LAST_ARRAY_ELEMENT.equals(token)) { | ||
| target.add(value); | ||
| return ret; | ||
| } | ||
|
|
@@ -132,8 +131,8 @@ private JsonNode addToArray(final JsonPointer path, final JsonNode node) | |
| private JsonNode addToObject(final JsonPointer path, final JsonNode node) | ||
| { | ||
| final JsonNode ret = node.deepCopy(); | ||
| final ObjectNode target = (ObjectNode) path.parent().get(ret); | ||
| target.put(Iterables.getLast(path).getToken().getRaw(), value); | ||
| final ObjectNode target = (ObjectNode) ret.at(head(path)); | ||
| target.put(JacksonUtils.getLast(path), value); | ||
| return ret; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| /* | ||
| * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com) | ||
| * | ||
| * This software is dual-licensed under: | ||
| * | ||
| * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any | ||
| * later version; | ||
| * - the Apache Software License (ASL) version 2.0. | ||
| * | ||
| * The text of this file and of both licenses is available at the root of this | ||
| * project or, if you have the jar distribution, in directory META-INF/, under | ||
| * the names LGPL-3.0.txt and ASL-2.0.txt respectively. | ||
| * | ||
| * Direct link to the sources: | ||
| * | ||
| * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt | ||
| * - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt | ||
| */ | ||
|
|
||
| package com.github.fge.jsonpatch; | ||
|
|
||
|
|
||
| import com.fasterxml.jackson.core.JsonPointer; | ||
| import com.fasterxml.jackson.databind.DeserializationFeature; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
| import com.fasterxml.jackson.databind.ObjectReader; | ||
| import com.fasterxml.jackson.databind.SerializationFeature; | ||
| import com.fasterxml.jackson.databind.node.JsonNodeFactory; | ||
|
|
||
| public final class JacksonUtils { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This class contains methods that does not implement natively the Jackson JsonPointer class. |
||
|
|
||
| private final static JsonNodeFactory FACTORY = JsonNodeFactory.instance; | ||
| private final static int NO_SLASH = -1; | ||
| private final static ObjectReader READER; | ||
|
|
||
| static { | ||
| final ObjectMapper mapper = newMapper(); | ||
| READER = mapper.reader(); | ||
| } | ||
|
|
||
| private JacksonUtils() | ||
| { | ||
| } | ||
|
|
||
| public final static ObjectMapper newMapper() { | ||
| return new ObjectMapper().setNodeFactory(FACTORY) | ||
| .enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS) | ||
| .enable(SerializationFeature.WRITE_BIGDECIMAL_AS_PLAIN) | ||
| .enable(SerializationFeature.INDENT_OUTPUT); | ||
| } | ||
|
|
||
| /** | ||
| * Return a preconfigured {@link ObjectReader} to read JSON inputs | ||
| * | ||
| * @return the reader | ||
| * @see #newMapper() | ||
| */ | ||
| public static ObjectReader getReader() | ||
| { | ||
| return READER; | ||
| } | ||
|
|
||
| /** | ||
| * Return a preconfigured {@link JsonNodeFactory} to generate JSON data as | ||
| * {@link com.fasterxml.jackson.databind.JsonNode}s | ||
| * | ||
| * @return the factory | ||
| */ | ||
| public final static JsonNodeFactory nodeFactory() | ||
| { | ||
| return FACTORY; | ||
| } | ||
|
|
||
| public final static String getLast(JsonPointer jsonPointer) | ||
| { | ||
| String representation = jsonPointer.toString(); | ||
|
|
||
| if(representation == null) return ""; | ||
|
|
||
| int slashPosition = -1; | ||
| if((slashPosition = representation.lastIndexOf('/')) != -1) | ||
| { | ||
| return representation.substring(slashPosition+1); | ||
| } | ||
| else | ||
| { | ||
| return representation; | ||
| } | ||
|
|
||
|
|
||
| } | ||
|
|
||
| public final static JsonPointer empty() | ||
| { | ||
| return JsonPointer.compile(""); | ||
| } | ||
|
|
||
| public final static JsonPointer head(JsonPointer jsonPointer) | ||
| { | ||
| String pointer = jsonPointer.toString(); | ||
|
|
||
| int lastSlash = pointer.lastIndexOf('/'); | ||
|
|
||
| if(lastSlash == NO_SLASH) | ||
| { | ||
| return empty(); | ||
| } | ||
| else | ||
| { | ||
| return JsonPointer.compile(pointer.substring(0, lastSlash)); | ||
| } | ||
| } | ||
|
|
||
| public final static JsonPointer append(JsonPointer pointer, String raw) | ||
| { | ||
| String p = pointer.toString(); | ||
| return JsonPointer.compile(p + "/" + raw); | ||
| } | ||
|
|
||
| public final static JsonPointer append(JsonPointer pointer, int raw) | ||
| { | ||
| String p = pointer.toString(); | ||
| return JsonPointer.compile(p + "/" + Integer.toString(raw)); | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| /* | ||
| * Copyright (c) 2014, Francis Galiegue (fgaliegue@gmail.com) | ||
| * | ||
| * This software is dual-licensed under: | ||
| * | ||
| * - the Lesser General Public License (LGPL) version 3.0 or, at your option, any | ||
| * later version; | ||
| * - the Apache Software License (ASL) version 2.0. | ||
| * | ||
| * The text of this file and of both licenses is available at the root of this | ||
| * project or, if you have the jar distribution, in directory META-INF/, under | ||
| * the names LGPL-3.0.txt and ASL-2.0.txt respectively. | ||
| * | ||
| * Direct link to the sources: | ||
| * | ||
| * - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt | ||
| * - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt | ||
| */ | ||
|
|
||
| package com.github.fge.jsonpatch; | ||
|
|
||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.node.JsonNodeType; | ||
|
|
||
| import java.util.HashSet; | ||
| import java.util.Iterator; | ||
| import java.util.Set; | ||
|
|
||
| public class JsonNumEquals | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Equivalence class but without dependency to Guava. |
||
| { | ||
|
|
||
| public static boolean equivalent(final JsonNode a, final JsonNode b) | ||
| { | ||
| /* | ||
| * If both are numbers, delegate to the helper method | ||
| */ | ||
| if (a.isNumber() && b.isNumber()) | ||
| return numEquals(a, b); | ||
|
|
||
| final JsonNodeType typeA = a.getNodeType(); | ||
| final JsonNodeType typeB = b.getNodeType(); | ||
|
|
||
| /* | ||
| * If they are of different types, no dice | ||
| */ | ||
| if (typeA != typeB) | ||
| return false; | ||
|
|
||
| /* | ||
| * For all other primitive types than numbers, trust JsonNode | ||
| */ | ||
| if (!a.isContainerNode()) | ||
| return a.equals(b); | ||
|
|
||
| /* | ||
| * OK, so they are containers (either both arrays or objects due to the | ||
| * test on types above). They are obviously not equal if they do not | ||
| * have the same number of elements/members. | ||
| */ | ||
| if (a.size() != b.size()) | ||
| return false; | ||
|
|
||
| /* | ||
| * Delegate to the appropriate method according to their type. | ||
| */ | ||
| return typeA == JsonNodeType.ARRAY ? arrayEquals(a, b) : objectEquals(a, b); | ||
| } | ||
|
|
||
| private static boolean numEquals(final JsonNode a, final JsonNode b) | ||
| { | ||
| /* | ||
| * If both numbers are integers, delegate to JsonNode. | ||
| */ | ||
| if (a.isIntegralNumber() && b.isIntegralNumber()) | ||
| return a.equals(b); | ||
|
|
||
| /* | ||
| * Otherwise, compare decimal values. | ||
| */ | ||
| return a.decimalValue().compareTo(b.decimalValue()) == 0; | ||
| } | ||
|
|
||
| private static boolean arrayEquals(final JsonNode a, final JsonNode b) | ||
| { | ||
| /* | ||
| * We are guaranteed here that arrays are the same size. | ||
| */ | ||
| final int size = a.size(); | ||
|
|
||
| for (int i = 0; i < size; i++) | ||
| if (!equivalent(a.get(i), b.get(i))) | ||
| return false; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| private static boolean objectEquals(final JsonNode a, final JsonNode b) | ||
| { | ||
| /* | ||
| * Grab the key set from the first node | ||
| */ | ||
| final Set<String> keys = newHashSet(a.fieldNames()); | ||
|
|
||
| /* | ||
| * Grab the key set from the second node, and see if both sets are the | ||
| * same. If not, objects are not equal, no need to check for children. | ||
| */ | ||
| final Set<String> set = newHashSet(b.fieldNames()); | ||
| if (!set.equals(keys)) | ||
| return false; | ||
|
|
||
| /* | ||
| * Test each member individually. | ||
| */ | ||
| for (final String key: keys) | ||
| if (!equivalent(a.get(key), b.get(key))) | ||
| return false; | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| private static Set<String> newHashSet(Iterator<String> fields) { | ||
| final Set<String> elements = new HashSet<String>(); | ||
|
|
||
| while(fields.hasNext()) { | ||
| elements.add(fields.next()); | ||
| } | ||
|
|
||
| return elements; | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Jackson JsonPointer does not have an empty method. For this reason we created an empty JsonPointer.