From 1a0cf3ec1eea2f111ff51d3f3fdfee12ec9592fe Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Tue, 5 Apr 2016 22:38:36 +0300 Subject: [PATCH 01/18] introduce helper classes to process a JSONObject and its nodes --- .../net/minidev/json/actions/PathLocator.java | 66 +++++ .../net/minidev/json/actions/PathRemover.java | 74 ++++++ .../minidev/json/actions/PathReplicator.java | 75 ++++++ .../minidev/json/actions/PathsRetainer.java | 85 ++++++ .../actions/navigate/CopyPathsAction.java | 141 ++++++++++ .../json/actions/navigate/JSONNavigator.java | 189 ++++++++++++++ .../json/actions/navigate/JSONPath.java | 243 ++++++++++++++++++ .../json/actions/navigate/NavigateAction.java | 102 ++++++++ .../json/actions/navigate/package-info.java | 28 ++ .../json/actions/traverse/JSONTraverser.java | 84 ++++++ .../actions/traverse/LocatePathsAction.java | 85 ++++++ .../json/actions/traverse/RemoveAction.java | 82 ++++++ .../json/actions/traverse/RetainAction.java | 114 ++++++++ .../json/actions/traverse/TraverseAction.java | 62 +++++ .../json/actions/traverse/package-info.java | 31 +++ .../json/test/actions/JSONPathTest.java | 93 +++++++ .../json/test/actions/PathLocatorTest.java | 159 ++++++++++++ .../json/test/actions/PathRemoverTest.java | 136 ++++++++++ .../json/test/actions/PathReplicatorTest.java | 232 +++++++++++++++++ .../json/test/actions/PathsRetainerTest.java | 168 ++++++++++++ 20 files changed, 2249 insertions(+) create mode 100755 json-smart/src/main/java/net/minidev/json/actions/PathLocator.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/PathRemover.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java create mode 100644 json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java create mode 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java create mode 100755 json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java create mode 100755 json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java create mode 100755 json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java create mode 100755 json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java create mode 100755 json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java new file mode 100755 index 00000000..1e80a1f1 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java @@ -0,0 +1,66 @@ +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.LocatePathsAction; +import net.minidev.json.actions.traverse.TraverseAction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Searches for paths in a {@link JSONObject} and returns those found. + *

+ * Traverses the specified {@link JSONObject} searching for nodes whose paths (from the root down) match + * any of the user-specified paths. The paths that match are returned. + *

+ * A path to locate must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * + * @author adoneitan@gmail.com + */ +public class PathLocator +{ + private List pathsToFind; + + public PathLocator(JSONArray pathsToFind) + { + if (pathsToFind == null || pathsToFind.isEmpty()) { + this.pathsToFind = Collections.emptyList(); + } + else + { + this.pathsToFind = new ArrayList(); + for (Object s : pathsToFind) { + this.pathsToFind.add((String) s); + } + } + } + + public PathLocator(List pathsToFind) + { + this.pathsToFind = pathsToFind == null || pathsToFind.size() == 0 ? + Collections.emptyList() : pathsToFind; + } + + public PathLocator(String... pathsToFind) + { + this.pathsToFind = pathsToFind == null || pathsToFind.length == 0 ? + Collections.emptyList() : Arrays.asList(pathsToFind); + } + + public List find(JSONObject object) + { + TraverseAction action = new LocatePathsAction(this.pathsToFind); + JSONTraverser traversal = new JSONTraverser(action); + traversal.traverse(object); + return (List) action.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java new file mode 100755 index 00000000..fb3e1bd8 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java @@ -0,0 +1,74 @@ +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.RemoveAction; +import net.minidev.json.actions.traverse.TraverseAction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Removes branches of nodes from a {@link JSONObject} matching the list of user-specified paths. + *

+ * A path to remove must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * Usage Example: + *

+ * To remove the field k1.k2 from the {@link JSONObject} {k1:{k2:v2}, k3:{k4:v4}} use the remover like so: + *

+ * PathRemover pr = new PathRemover("k1.k2");
+ * JSONObject cleanObject = pr.remove(new JSONObject(...));
+ * 
+ * The resulting object 'cleanObject' would be {k1:{k3:{k4:v4}}} + *

+ * See unit tests for more examples + * + * @author adoneitan@gmail.com + * + */ +public class PathRemover +{ + private List pathsToRemove; + + public PathRemover(JSONArray pathsToRemove) + { + if (pathsToRemove == null || pathsToRemove.isEmpty()) { + this.pathsToRemove = Collections.emptyList(); + } + else + { + this.pathsToRemove = new ArrayList(); + for (Object s : pathsToRemove) { + this.pathsToRemove.add((String) s); + } + } + } + + public PathRemover(List pathsToRemove) + { + this.pathsToRemove = pathsToRemove == null || pathsToRemove.size() == 0 ? + Collections.emptyList() : pathsToRemove; + } + + public PathRemover(String... pathsToRemove) + { + this.pathsToRemove = pathsToRemove == null || pathsToRemove.length == 0 ? + Collections.emptyList() : Arrays.asList(pathsToRemove); + } + + public JSONObject remove(JSONObject objectToClean) + { + TraverseAction strategy = new RemoveAction(this.pathsToRemove); + JSONTraverser traversal = new JSONTraverser(strategy); + traversal.traverse(objectToClean); + return (JSONObject) strategy.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java new file mode 100755 index 00000000..b708374f --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java @@ -0,0 +1,75 @@ +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.navigate.CopyPathsAction; +import net.minidev.json.actions.navigate.JSONNavigator; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * Creates a copy of a {@link JSONObject} consisting only of the nodes on the user-specified paths. + *

+ * Paths that do not exist in the specified object are ignored silently. Specifying an empty list of paths + * to copy or only non-existent paths will result in an empty object being returned. + *

+ * A path to copy must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * Sample usage: + *

+ * To replicate the branch k1.k2 from {k1:{k2:v2}, k3:{k4:v4}} use the {@link PathReplicator} like so: + *

+ * PathReplicator pr = new {@link PathReplicator}("k1.k2")
+ * JSONObject copiedObject = pr.copy(new JSONObject(...))
+ * 
+ * The resulting object 'copiedObject' would be {k1:{k2:v2}} + *

+ * see unit tests for more examples + * + * @author adoneitan@gmail.com + */ +public class PathReplicator +{ + protected List pathsToCopy; + + public PathReplicator(JSONArray pathsToCopy) + { + if (pathsToCopy == null || pathsToCopy.isEmpty()) { + this.pathsToCopy = Collections.emptyList(); + } + else + { + this.pathsToCopy = new LinkedList(); + for (Object s : pathsToCopy) { + this.pathsToCopy.add((String) s); + } + } + } + + public PathReplicator(List pathsToCopy) + { + this.pathsToCopy = pathsToCopy == null || pathsToCopy.size() == 0 ? + Collections.emptyList() : pathsToCopy; + } + + public PathReplicator(String... pathsToCopy) + { + this.pathsToCopy = pathsToCopy == null || pathsToCopy.length == 0 ? + Collections.emptyList() : new LinkedList(Arrays.asList(pathsToCopy)); + } + + public JSONObject replicate(JSONObject sourceObj) throws Exception + { + CopyPathsAction s = new CopyPathsAction(); + JSONNavigator n = new JSONNavigator(s, pathsToCopy); + n.nav(sourceObj); + return (JSONObject) s.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java new file mode 100755 index 00000000..6dc146dd --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java @@ -0,0 +1,85 @@ +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.traverse.RetainAction; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.LocatePathsAction; +import net.minidev.json.actions.traverse.TraverseAction; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * Retains branches of nodes of a {@link JSONObject} matching the list of user-specified paths. + *

+ * A path to copy must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * Example: + *

+ * to retain the field k1.k2 in the {@link JSONObject} {k1:{k2:v1}, k3:{k4:v2}} instantiate the retainer like so: + * new JSONObjectCleaner("k1.k2") + * The resulting object would be {k1:{k2:v1}} + *

+ * See unit tests in JSONObjectRetainerTest for more examples + * + * @author adoneitan@gmail.com + */ +public class PathsRetainer +{ + protected List pathsToRetain; + + public PathsRetainer(JSONArray pathsToRetain) + { + if (pathsToRetain == null || pathsToRetain.isEmpty()) { + this.pathsToRetain = Collections.emptyList(); + } + else + { + this.pathsToRetain = new LinkedList(); + for (Object s : pathsToRetain) { + this.pathsToRetain.add((String) s); + } + } + } + + public PathsRetainer(List pathsToRetain) + { + this.pathsToRetain = pathsToRetain == null || pathsToRetain.size() == 0 ? + Collections.emptyList() : pathsToRetain; + } + + public PathsRetainer(String... pathsToRetain) + { + this.pathsToRetain = pathsToRetain == null || pathsToRetain.length == 0 ? + Collections.emptyList() : new LinkedList(Arrays.asList(pathsToRetain)); + } + + public JSONObject retain(JSONObject object) + { + /** + * a path to retain which contains a path in the object, but is not itself a path in the object, + * will cause the sub-path to be retain although it shouldn't: + * object = {k0:v0} retain = {k0.k1} + * so the false path to retain has to be removed from the pathsToRetain list. + * + * The {@link LocatePathsAction} returns only paths which exist in the object. + */ + TraverseAction locateAction = new LocatePathsAction(pathsToRetain); + JSONTraverser t1 = new JSONTraverser(locateAction); + t1.traverse(object); + List realPathsToRetain = (List) locateAction.result(); + + //now reduce the object using only existing paths + TraverseAction reduce = new RetainAction(realPathsToRetain); + JSONTraverser t2 = new JSONTraverser(reduce); + t2.traverse(object); + return (JSONObject) reduce.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java new file mode 100755 index 00000000..e044167c --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -0,0 +1,141 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +import java.util.Collection; +import java.util.Stack; + +/** + * Creates a copy of a {@link JSONObject} containing just the nodes on the paths specified. + *

+ * Specified paths that do not exist in the source object are ignored silently. + * Specifying an empty list of paths to navigate or only non-existent paths will result in an empty + * object being returned. + *

+ * See package-info for more details + *

+ * Example: + *

+ * To copy the branch k1.k2 from {k1:{k2:v1}, k3:{k4:v2}} instantiate the copier like so: + * new JSONObjectCopier("k1.k2") + * The resulting copy would be {k1:{k2:v1}} + *

+ * See unit tests for more examples + * + * @author adoneitan@gmail.com + * + */ +public class CopyPathsAction implements NavigateAction +{ + private JSONObject destTree; + private JSONObject destBranch; + private Stack destNodeStack; + + @Override + public boolean handleNavigationStart(JSONObject source, Collection pathsToCopy) + { + if (source == null) + { + destTree = null; + return false; + } + + destTree = new JSONObject(); + if (pathsToCopy == null || pathsToCopy.size() == 0) { + return false; + } + + /** + * using ARRAY_PUSH which adds any new entry encountered in arrays, effectively + * allowing duplicate objects in the array, which is supported by Gigya + */ + return true; + } + + @Override + public boolean handleObjectStartAndRecur(JSONPath jp, JSONObject o) + { + //reached JSONObject node - instantiate it and recur + handleNewNode(jp, new JSONObject()); + return true; + } + + private void handleNewNode(JSONPath jp, Object node) + { + if (destNodeStack.peek() instanceof JSONObject) { + ((JSONObject) destNodeStack.peek()).put(jp.curr(), node); + } + else if (destNodeStack.peek() instanceof JSONArray) { + ((JSONArray) destNodeStack.peek()).add(node); + } + destNodeStack.push(node); + } + + @Override + public boolean handleArrayStartAndRecur(JSONPath jp, JSONArray o) + { + //reached JSONArray node - instantiate it and recur + handleNewNode(jp, new JSONArray()); + return true; + } + + @Override + public void handlePrematureNavigatedBranchEnd(JSONPath jp, Object source) { + throw new IllegalArgumentException("branch is shorter than path - path not found in source: '" + jp.origin() + "'"); + } + + @Override + public void handleObjectLeaf(JSONPath jp, Object o) { + ((JSONObject) destNodeStack.peek()).put(jp.curr(), o); + } + + @Override + public void handleArrayLeaf(int arrIndex, Object o) { + ((JSONArray) destNodeStack.peek()).add(o); + } + + @Override + public void handleArrayEnd(JSONPath jp) { + destNodeStack.pop(); + } + + @Override + public void handleObjectEnd(JSONPath jp) { + destNodeStack.pop(); + } + + @Override + public boolean handleNextPath(String path) + { + destBranch = new JSONObject(); + destNodeStack = new Stack(); + destNodeStack.push(destBranch); + return true; + } + + @Override + public void handlePathEnd(String path) { + destTree.merge(destBranch); + } + + @Override + public boolean failPathSilently(String path, Exception e) { + return false; + } + + @Override + public boolean failPathFast(String path, Exception e) { + return false; + } + + @Override + public void handleNavigationEnd() { + + } + + @Override + public Object result() { + return destTree; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java new file mode 100755 index 00000000..b5789af9 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java @@ -0,0 +1,189 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * Navigates only the branches of a {@link JSONObject} corresponding to the paths specified. + *

+ * For each specified path to navigate, the {@link JSONNavigator} only traverses the matching + * branch. + *

+ * The navigator accepts an action and provides callback hooks for it to act on the traversed + * nodes at each significant step. See {@link NavigateAction}. + *

+ * See package-info for more details + *

+ * Example: + *

+ * To navigate the branch k1.k2 of the object {"k1":{"k2":"v1"}, "k3":{"k4":"v2"}} instantiate + * the navigator like so: new JSONNavigator("k1.k2") + * + * @author adoneitan@gmail.com + * + */ +public class JSONNavigator +{ + protected List pathsToNavigate; + protected NavigateAction action; + + public JSONNavigator(NavigateAction action, JSONArray pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("NavigateAction cannot be null"); + } + this.action = action; + if (pathsToNavigate == null || pathsToNavigate.isEmpty()) { + this.pathsToNavigate = Collections.emptyList(); + } + else + { + this.pathsToNavigate = new LinkedList(); + for (Object s : pathsToNavigate) { + this.pathsToNavigate.add((String) s); + } + } + } + + public JSONNavigator(NavigateAction action, List pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("NavigateAction cannot be null"); + } + this.action = action; + this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.size() == 0 ? + Collections.emptyList() : pathsToNavigate; + } + + public JSONNavigator(NavigateAction action, String... pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("NavigateAction cannot be null"); + } + this.action = action; + this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.length == 0 ? + Collections.emptyList() : new LinkedList(Arrays.asList(pathsToNavigate)); + } + + public void nav(JSONObject object) throws Exception + { + if (action.handleNavigationStart(object, pathsToNavigate)) + { + for (String path: pathsToNavigate) + { + try + { + if (path != null && !path.equals("") && action.handleNextPath(path)) + { + JSONPath jp = new JSONPath(path); + nav(object, jp); + action.handlePathEnd(path); + } + } + catch (Exception e) + { + if (action.failPathSilently(path ,e)) { + break; + } + else if (action.failPathFast(path, e)) { + throw e; + } + } + } + } + action.handleNavigationEnd(); + } + + private void nav(JSONObject source, JSONPath jp) + { + if (jp.hasNext()) + { + if (source == null) + { + //source is null - navigation impossible + return; + } + String next = jp.next(); + if (!source.containsKey(next)) + { + // reached end of branch in source before end of specified json path - + // the specified path is illegal because it does not exist in the source. + action.handlePrematureNavigatedBranchEnd(jp, source); + } + else if (source.get(next) instanceof JSONObject && action.handleObjectStartAndRecur(jp, (JSONObject) source.get(next))) + { + //reached JSONObject node - handle it and recur into it + nav((JSONObject) source.get(next), jp); + } + else if (source.get(next) instanceof JSONArray && action.handleArrayStartAndRecur(jp, (JSONArray) source.get(next))) + { + //reached JSONArray node - handle it and recur into it + nav((JSONArray) source.get(next), jp); + } + else if (jp.hasNext()) + { + // reached leaf node (not a container) in source but specified path expects children - + // the specified path is illegal because it does not exist in the source. + action.handlePrematureNavigatedBranchEnd(jp, source.get(next)); + } + else if (!jp.hasNext()) + { + //reached leaf in source and specified path is also at leaf -> handle it + action.handleObjectLeaf(jp, source.get(next)); + } + else + { + throw new IllegalStateException("fatal: unreachable code reached at '" + jp.origin() + "'"); + } + } + action.handleObjectEnd(jp); + } + + private void nav(JSONArray source, JSONPath jp) + { + if (source == null) + { + //array is null - navigation impossible + return; + } + int arrIndex = 0; + for (Object arrItem : source.toArray()) + { + if (arrItem instanceof JSONObject && action.handleObjectStartAndRecur(jp, (JSONObject) arrItem)) + { + // clone the path so that for each JSONObject in the array, + // the iterator continues from the same position in the path + JSONPath jpClone = getClone(jp); + nav((JSONObject) arrItem, jpClone); + } + else if (arrItem instanceof JSONArray) + { + throw new IllegalArgumentException("illegal json - found array nested inside array at: '" + jp.origin() + "'"); + } + else if (!jp.hasNext()) + { + //reached leaf - handle it + action.handleArrayLeaf(arrIndex, arrItem); + } + arrIndex++; + } + action.handleArrayEnd(jp); + + } + + private JSONPath getClone(JSONPath jp) + { + try + { + return jp.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException("failed to clone json path", e); + } + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java new file mode 100755 index 00000000..2bf589ff --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java @@ -0,0 +1,243 @@ +package net.minidev.json.actions.navigate; + + +import net.minidev.json.JSONObject; + +import java.util.Arrays; +import java.util.List; +import java.util.ListIterator; + +/** + * {@link JSONPath} represents an n-gram formatted path + * corresponding to a branch in a {@link JSONObject} + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public class JSONPath +{ + protected enum Step {NONE, NEXT, PREV} + protected final String path; + protected List keys; + protected ListIterator keysItr; + protected String currKey; + protected Step lastStep; + protected StringBuilder origin; + protected StringBuilder remainder; + + public JSONPath(String path) + { + checkPath(path); + this.path = path; + this.keys = Arrays.asList(path.split("\\.")); + reset(); + } + + public void reset() + { + keysItr = keys.listIterator(); + currKey = ""; + lastStep = Step.NONE; + origin = new StringBuilder(""); + remainder = new StringBuilder(path); + } + + public boolean hasNext() { + return keysItr.hasNext(); + } + + public int nextIndex() { + return keysItr.nextIndex(); + } + + public String next() + { + currKey = keysItr.next(); + /** when changing direction the {@link ListIterator} does not really + * move backward so an extra step is performed */ + if (!lastStep.equals(Step.PREV)) { + originIncrement(); + remainderDecrement(); + } + lastStep = Step.NEXT; + return currKey; + } + + public boolean hasPrev() { + return keysItr.hasPrevious(); + } + + public int prevIndex() { + return keysItr.previousIndex(); + } + + public String prev() + { + String temp = currKey; + currKey = keysItr.previous(); + /** when changing direction the {@link ListIterator} does not really + * move backward so an extra step is performed */ + if (!lastStep.equals(Step.NEXT)) { + remainderIncrement(temp); + originDecrement(); + } + lastStep = Step.PREV; + return currKey; + } + + private void remainderDecrement() + { + if (length() == 1) + remainder = new StringBuilder(""); + else if (remainder.indexOf(".") < 0) + remainder = new StringBuilder(""); + else + remainder.delete(0, remainder.indexOf(".") + 1); + } + + private void originDecrement() + { + if (length() == 1) + origin = new StringBuilder(""); + else if (origin.indexOf(".") < 0) + origin = new StringBuilder(""); + else + origin.delete(origin.lastIndexOf("."), origin.length()); + } + + private void originIncrement() + { + if (origin.length() != 0) { + origin.append('.'); + } + origin.append(currKey); + } + + private void remainderIncrement(String prev) + { + if (remainder.length() == 0) + remainder = new StringBuilder(prev); + else + remainder = new StringBuilder(prev).append('.').append(remainder); + } + + /** + * @return An n-gram path from the first key to the current key (inclusive) + */ + public String path() { + return path; + } + + /** + * @return An n-gram path from the first key to the current key (inclusive) + */ + public String origin() { + return origin.toString(); + } + + /** + * @return An n-gram path from the current key to the last key (inclusive) + */ + public String remainder() { + return remainder.toString(); + } + + /** + * @return first element in the JSONPath + */ + public String first() { + return keys.get(0); + } + + /** + * @return last element in the JSONPath + */ + public String last() { + return keys.get(keys.size() - 1); + } + + /** + * @return current element pointed to by the path iterator + */ + public String curr() { + return currKey; + } + + public int length() { + return keys.size(); + } + + public String subPath(int firstIndex, int lastIndex) + { + if (lastIndex < firstIndex) { + throw new IllegalArgumentException("bad call to subPath"); + } + StringBuilder sb = new StringBuilder(path.length()); + for (int i = firstIndex; i <= lastIndex; i++) + { + sb.append(keys.get(i)); + if (i < lastIndex) { + sb.append('.'); + } + } + sb.trimToSize(); + return sb.toString(); + } + + private void checkPath(String path) + { + if (path == null || path.equals("")) + throw new IllegalArgumentException("path cannot be null or empty"); + if (path.startsWith(".") || path.endsWith(".") || path.contains("src/main")) + throw new IllegalArgumentException("path cannot start or end with '.' or contain '..'"); + } + + @Override + public JSONPath clone() throws CloneNotSupportedException + { + JSONPath cloned = new JSONPath(this.path); + while (cloned.nextIndex() != this.nextIndex()) { + cloned.next(); + } + if (cloned.prevIndex() != this.prevIndex()) { + cloned.prev(); + } + cloned.lastStep = this.lastStep; + cloned.currKey = new String(this.currKey); + cloned.origin = new StringBuilder(this.origin); + cloned.remainder = new StringBuilder(this.remainder); + return cloned; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + JSONPath jsonPath = (JSONPath) o; + + return path().equals(jsonPath.path()) && + hasNext() == jsonPath.hasNext() && + hasPrev() == jsonPath.hasPrev() && + curr().equals(jsonPath.curr()) && + origin().equals(jsonPath.origin()) && + remainder().equals(jsonPath.remainder()) && + lastStep == jsonPath.lastStep; + + } + + @Override + public int hashCode() { + int result = path.hashCode(); + result = 31 * result + keys.hashCode(); + result = 31 * result + keysItr.hashCode(); + result = 31 * result + currKey.hashCode(); + result = 31 * result + lastStep.hashCode(); + result = 31 * result + origin.hashCode(); + result = 31 * result + remainder.hashCode(); + return result; + } +} + + diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java new file mode 100755 index 00000000..72af94f7 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java @@ -0,0 +1,102 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +import java.util.Collection; + +/** + * An interface for a processing action on the nodes of a {@link JSONObject} while navigating its branches. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public interface NavigateAction +{ + /** + * called before any navigation of the {@link JSONObject} starts + * @return true if navigation should start at all + */ + boolean handleNavigationStart(JSONObject objectToNavigate, Collection pathsToNavigate); + + /** + * called before navigation of a new path starts + * @return true if the specified path should be navigated + */ + boolean handleNextPath(String path); + + /** + * reached end of branch in source before end of specified json path - + * the specified path does not exist in the source. + */ + void handlePrematureNavigatedBranchEnd(JSONPath jp, Object source); + + /** + * called after the navigation of a path ends + */ + void handlePathEnd(String path); + + /** + * called if navigation of a path throws an exception + * @return true if the failure on this path should not abort the rest of the navigation + */ + boolean failPathSilently(String path, Exception e); + + /** + * called if navigation of a path throws an exception + * @return true if the failure on this path should abort the rest of the navigation + */ + boolean failPathFast(String path, Exception e); + + /** + * called when an object node is encountered on the path + * @return true if the navigator should navigate into the object + */ + boolean handleObjectStartAndRecur(JSONPath jp, JSONObject sourceNode); + + /** + * called when an array node is encountered on the path + * @return true if the navigator should navigate into the array + */ + boolean handleArrayStartAndRecur(JSONPath jp, JSONArray sourceNode); + + /** + * called when a leaf node is reached in a JSONObject. + * a leaf in a JSONObject is a key-value pair where the value is not a container itself + * (it is not a JSONObject nor a JSONArray) + * @param jp - the JsonPath pointing to the leaf + */ + void handleObjectLeaf(JSONPath jp, Object value); + + /** + * called when a leaf in a JSONArray is reached. + * a leaf in a JSONArray is a non-container item + * (it is not a JSONObject nor a JSONArray) + * @param arrIndex - the index of the item in the JSONArray + * @param arrItem - the item + */ + void handleArrayLeaf(int arrIndex, Object arrItem); + + /** + * called after all the items of an array have been visited + * @param jp - the JsonPath pointing to the array + */ + void handleArrayEnd(JSONPath jp); + + /** + * called after all the entries of a JSONObject have been visited + * @param jp - the JsonPath pointing to the object + */ + void handleObjectEnd(JSONPath jp); + + /** + * called after all navigation ends, and just before the navigation method exits + */ + void handleNavigationEnd(); + + /** + * holds the result of the navigation, as assigned by the action implementing this interface + */ + Object result(); +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java new file mode 100644 index 00000000..537cf36e --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java @@ -0,0 +1,28 @@ +/** + * Navigate user-specified paths in a {@link net.minidev.json.JSONObject} and process them + *

+ * {@link net.minidev.json.actions.navigate.JSONNavigator} only navigates through branches corresponding + * to user-specified paths. For each path, the navigation starts at the root and moves down the branch. + *

+ * The {@link net.minidev.json.actions.navigate.JSONNavigator} accepts a + * {@link net.minidev.json.actions.navigate.NavigateAction} and provides callback hooks at each significant + * step which the {@link net.minidev.json.actions.navigate.NavigateAction} may use to process + * the nodes. + *

+ * A path to navigate must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * Sample usage: + *

+ * NavigateAction navAction = new NavigateAction(){...};
+ * JSONNavigator jsonNav = new JSONNavigator(navAction, "foo.bar.path");
+ * jsonNav.nav(new JSONObject(...));
+ * Object result = navAction.result();
+ * 
+ * + * @author adoneitan@gmail.com + */ +package net.minidev.json.actions.navigate; \ No newline at end of file diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java new file mode 100755 index 00000000..ce543a20 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java @@ -0,0 +1,84 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +import java.util.Iterator; +import java.util.Map; + +/** + * Traverses every node of a {@link JSONObject} + *

+ * {@link JSONTraverser} accepts an action and provides callback hooks for it to act + * on the traversed nodes at each significant step. See {@link TraverseAction}. + *

+ * A key to the right of a dot is a direct child of a key to the left of a dot. + * Keys with a dot in their name are not supported. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + * + */ +public class JSONTraverser +{ + private TraverseAction action; + + public JSONTraverser(TraverseAction action) + { + this.action = action; + } + + public void traverse(JSONObject object) + { + if (action.handleStart(object)){ + breadthFirst("", object); + } + action.handleEnd(); + } + + private void breadthFirst(String fullPathToObject, JSONObject jsonObject) + { + if (jsonObject == null || jsonObject.entrySet() == null) { + return; + } + Iterator> it = jsonObject.entrySet().iterator(); + while (it.hasNext() && action.handleNext()) + { + Map.Entry entry = it.next(); + if (entry.getKey().contains(".") && !action.handleDotChar()) + { + //a dot char '.' in the key is not supported by the action, abandon this path + continue; + } + String fullPathToEntry = "".equals(fullPathToObject) ? entry.getKey() : fullPathToObject + "." + entry.getKey(); + if (action.handleEntryAndIgnoreChildren(fullPathToEntry, it, entry)) + { + continue; + } + else if (entry.getValue() instanceof JSONObject && action.handleJSONObjectChild()) + { + breadthFirst(fullPathToEntry, (JSONObject) entry.getValue()); + } + else if (entry.getValue() instanceof JSONArray && action.handleJSONArrayChild()) + { + breadthFirst(fullPathToEntry, (JSONArray) entry.getValue()); + } + } + } + + private void breadthFirst(String fullPathToObject, JSONArray jsonArray) + { + for (Object arrItem : jsonArray.toArray()) + { + if (arrItem instanceof JSONObject) + { + breadthFirst(fullPathToObject, (JSONObject) arrItem); + } + else if (arrItem instanceof JSONArray) + { + breadthFirst(fullPathToObject, (JSONArray) arrItem); + } + } + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java new file mode 100755 index 00000000..6d7a3709 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java @@ -0,0 +1,85 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONObject; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * Searches for paths in a {@link JSONObject} and returns those found + *

+ * A path is not removed from the user-specified list once its processing is over, + * because identical objects in the same array are supported by this action. + *

+ * See package-info for more details + *

+ * See unit tests for examples + * + * @author adoneitan@gmail.com + * + */ +public class LocatePathsAction implements TraverseAction +{ + protected List pathsFound; + protected List pathsToFind; + + /** + * + * @param pathsToFind A path to a field in the {@link JSONObject} should be specified in n-gram format where keys are chained: + * k0[[[.k1].k2]...] + */ + public LocatePathsAction(List pathsToFind) + { + this.pathsToFind = pathsToFind; + pathsFound = new LinkedList(); + } + + @Override + public boolean handleStart(JSONObject object) + { + return object != null && pathsToFind != null && pathsToFind.size() > 0; + } + + @Override + public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + { + if (pathsToFind.contains(pathToEntry)) + { + //reached end of path that is being searched + pathsFound.add(pathToEntry); + } + return false; + } + + @Override + public boolean handleDotChar() { + return false; + } + + @Override + public boolean handleNext() { + return true; + } + + @Override + public boolean handleJSONObjectChild() { + return true; + } + + @Override + public boolean handleJSONArrayChild() { + return true; + } + + @Override + public void handleEnd() { + //nothing to do + } + + @Override + public Object result() { + return pathsFound; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java new file mode 100755 index 00000000..00d9f8ef --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java @@ -0,0 +1,82 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONObject; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Removes branches from a {@link JSONObject}. + *

+ * A path is not removed from the user-specified list once its processing is over, + * because identical objects in the same array are supported by this action. + *

+ * See package-info for more details + *

+ * See unit tests for examples + * + * @author adoneitan@gmail.com + * + */ +public class RemoveAction implements TraverseAction +{ + protected JSONObject result; + protected List pathsToRemove; + + public RemoveAction(List pathsToRemove) + { + this.pathsToRemove = pathsToRemove; + } + + @Override + public boolean handleStart(JSONObject object) + { + result = object; + return object != null && pathsToRemove != null && pathsToRemove.size() > 0; + } + + @Override + public boolean handleDotChar() { + return true; + } + + @Override + public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + { + if (pathsToRemove.contains(pathToEntry)) + { + it.remove(); + //the entry has been removed from the traversal iterator, no point in traversing its children + return true; + } + return false; + } + + @Override + public boolean handleNext() + { + //must traverse the whole object + return true; + } + + @Override + public boolean handleJSONObjectChild() { + return true; + } + + @Override + public boolean handleJSONArrayChild() { + return true; + } + + @Override + public void handleEnd() { + //nothing to do + } + + @Override + public Object result() { + return result; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java new file mode 100755 index 00000000..1234ff65 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java @@ -0,0 +1,114 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONObject; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Retain branches or parts of branches matching a specified list of paths. + *

+ * Paths are matched from the root down. If a user-specified path ends at a non-leaf node, + * the rest of the branch from that node to the leaf is not retained. + *

+ * A path is not removed from the user-specified list once its processing is over, + * because identical objects in the same array are supported by this action. + *

+ * See package-info for more details + *

+ * See unit tests for examples + * + * @author adoneitan@gmail.com + * + */ +public class RetainAction implements TraverseAction +{ + protected JSONObject result; + protected List pathsToRetain; + + public RetainAction(List pathsToRetain) + { + this.pathsToRetain = new ArrayList(pathsToRetain); + } + + @Override + public boolean handleStart(JSONObject object) + { + if (object == null) + { + result = null; + return false; + } + if (pathsToRetain == null || pathsToRetain.size() == 0) + { + result = new JSONObject(); + return false; + } + result = object; + return true; + } + + @Override + public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + { + /** + * if the full path to the entry is not contained in any of the paths to retain - remove it from the object + * this step does not remove entries whose full path is contained in a path to retain but are not equal to an + * entry to retain + */ + if (!foundStartsWith(pathToEntry) || entry.getKey().contains(".")) + { + it.remove(); + //the entry has been removed from the traversal iterator, no point in traversing its children + return true; + } + return false; + } + + @Override + public boolean handleDotChar() + { + //need to reach handleEntryAndIgnoreChildren() in order to remove the path containing the dot char + return true; + } + + @Override + public boolean handleNext() + { + //must traverse the whole object + return true; + } + + @Override + public boolean handleJSONObjectChild() { + return true; + } + + @Override + public boolean handleJSONArrayChild(){ + return true; + } + + @Override + public void handleEnd() + { + // nothing to do + } + + @Override + public Object result() { + return result; + } + + protected boolean foundStartsWith(String path) + { + for (String p : pathsToRetain) { + if (p == path || (p != null && path != null && p.startsWith(path))) { + return true; + } + } + return false; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java new file mode 100755 index 00000000..6184c6f4 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java @@ -0,0 +1,62 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +import java.util.Iterator; +import java.util.Map; + +/** + * An interface for a processing action on the nodes of a {@link JSONObject} while traversing it. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public interface TraverseAction +{ + /** + * called before any traversal of the {@link JSONObject} starts + * @return true if traversal should start at all + */ + boolean handleStart(JSONObject object); + + /** + * @return false if encountering a key containing a '.' char on the path should abort the traversal of the path + */ + boolean handleDotChar(); + + /** + * called for each entry in given level of the {@link JSONObject} + * @return false if children of the specified entry should not be traversed + */ + boolean handleEntryAndIgnoreChildren(String fullPathToObject, Iterator> it, Map.Entry entry); + + /** + * called before the next entry in a given level of the {@link JSONObject} is processed + * @return true if siblings of the last entry should be processed + */ + boolean handleNext(); + + /** + * called if the child of the currently processed entry is a {@link JSONObject} + * @return true if a {@link JSONObject} child of the current entry should be processed + */ + boolean handleJSONObjectChild(); + + /** + * called if the child of the currently processed entry is a {@link JSONArray} + * @return true if a {@link JSONArray} child of the current entry should be processed + */ + boolean handleJSONArrayChild(); + + /** + * called after the traversal ends, and just before the traversal method exits + */ + void handleEnd(); + + /** + * holds the result of the traversal, as assigned by the action implementing this interface + */ + Object result(); +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java new file mode 100644 index 00000000..dcb334a3 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java @@ -0,0 +1,31 @@ +/** + * + * Traverse all the nodes in a {@link net.minidev.json.JSONObject} and process them + *

+ * The traversal starts at the root and moves breadth-first down the branches. + * The {@link net.minidev.json.actions.traverse.JSONTraverser} accepts a + * {@link net.minidev.json.actions.traverse.TraverseAction} and provides callback hooks at each significant + * step which the {@link net.minidev.json.actions.traverse.TraverseAction} may use to process + * the nodes. + *

+ * The {@link net.minidev.json.actions.traverse.JSONTraverser} assumes that paths in the tree which the + * {@link net.minidev.json.JSONObject} represents are specified in the n-gram format - a list of keys from the + * root down separated by dots: + *

+ * K0[[[[.K1].K2].K3]...] + *

+ * A key to the right of a dot is a direct child of a key to the left of a dot. + * Keys with a dot in their name are not supported. + *

+ * Sample usage: + *

+ * TraverseAction tAction = new TraverseAction(){...};
+ * JSONTraverser jsonTrv = new JSONTraverser(tAction);
+ * jsonTrv.traverse(new JSONObject(...));
+ * Object result = tAction.result();
+ * 
+ * + + * @author adoneitan@gmail.com + */ +package net.minidev.json.actions.traverse; \ No newline at end of file diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java new file mode 100755 index 00000000..54031296 --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java @@ -0,0 +1,93 @@ +package net.minidev.json.test.actions; + +import net.minidev.json.actions.navigate.JSONPath; +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * @author adoneitan@gmail.com + */ +public class JSONPathTest +{ + @Test + public void testIterator() + { + JSONPath jp = new JSONPath("a.b.c"); + assertTrue(jp.nextIndex() == 0); + assertTrue(jp.prevIndex() == -1); + assertTrue("".equals(jp.curr())); + assertTrue("".equals(jp.origin())); + assertTrue("a.b.c".equals(jp.remainder())); + assertTrue(jp.hasNext()); + assertFalse(jp.hasPrev()); + + jp.next(); + assertTrue("a".equals(jp.curr())); + assertTrue("a".equals(jp.origin())); + assertTrue("b.c".equals(jp.remainder())); + assertTrue(jp.hasNext()); + assertTrue(jp.hasPrev()); + + jp.next(); + assertTrue("b".equals(jp.curr())); + assertTrue("a.b".equals(jp.origin())); + assertTrue("c".equals(jp.remainder())); + assertTrue(jp.hasNext()); + assertTrue(jp.hasPrev()); + + jp.next(); + assertTrue("c".equals(jp.curr())); + assertTrue("a.b.c".equals(jp.origin())); + assertTrue("".equals(jp.remainder())); + assertFalse(jp.hasNext()); + assertTrue(jp.hasPrev()); + + /** the first prev() after a next only changes direction. see {@link ListIterator} for details */ + jp.prev(); + assertTrue("c".equals(jp.curr())); + assertTrue("a.b.c".equals(jp.origin())); + assertTrue("".equals(jp.remainder())); + assertTrue(jp.hasNext()); + assertTrue(jp.hasPrev()); + + jp.prev(); + assertTrue("b".equals(jp.curr())); + assertTrue("a.b".equals(jp.origin())); + assertTrue("c".equals(jp.remainder())); + assertTrue(jp.hasNext()); + assertTrue(jp.hasPrev()); + + jp.prev(); + assertTrue("a".equals(jp.curr())); + assertTrue("a".equals(jp.origin())); + assertTrue("b.c".equals(jp.remainder())); + assertTrue(jp.hasNext()); + assertFalse(jp.hasPrev()); + } + + @Test + public void testSubPath() + { + JSONPath jp = new JSONPath("a.b.c"); + assertTrue(jp.subPath(1,2).equals("b.c")); + } + + @Test + public void testClone() throws CloneNotSupportedException + { + JSONPath jp1 = new JSONPath("a.b.c"); + JSONPath jp2 = jp1.clone(); + assertTrue(jp1.equals(jp2)); + + jp1.next(); + JSONPath jp3 = jp1.clone(); + assertTrue(jp1.equals(jp3)); + + jp1.prev(); + JSONPath jp4 = jp1.clone(); + assertTrue(jp1.equals(jp4)); + + } +} \ No newline at end of file diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java new file mode 100755 index 00000000..890bbfcc --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java @@ -0,0 +1,159 @@ +package net.minidev.json.test.actions; + +import net.minidev.json.actions.PathLocator; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.parser.ParseException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class PathLocatorTest +{ + private String jsonToSearch; + private Object keysToFind; + private String[] expectedFound; + + public PathLocatorTest(String jsonToSearch, Object keysToFind, String[] expectedFound) + { + this.jsonToSearch = jsonToSearch; + this.keysToFind = keysToFind; + this.expectedFound = expectedFound; + } + + @Parameterized.Parameters + public static Collection params() + { + return Arrays.asList(new Object[][]{ + + //nulls, bad/empty keys + {null, null, new String[]{} }, + {null, "", new String[]{} }, + {null, "k1", new String[]{} }, + {null, new String[]{}, new String[]{} }, + {null, new JSONArray(), new String[]{} }, + {null, new ArrayList(0), new String[]{} },//5 + + //empty json, bad/empty keys + {"{}", null, new String[]{} }, + {"{}", "", new String[]{} }, + {"{}", "k1", new String[]{} }, + {"{}", new String[]{}, new String[]{} }, + {"{}", new JSONArray(), new String[]{} }, + {"{}", new ArrayList(0), new String[]{} },//11 + + //simple json, bad/empty keys + {"{\"k0\":\"v0\"}", null, new String[]{} }, + {"{\"k0\":\"v0\"}", "", new String[]{} }, + {"{\"k0\":\"v0\"}", "k1", new String[]{} }, + {"{\"k0\":\"v0\"}", new String[]{}, new String[]{} }, + {"{\"k0\":\"v0\"}", new JSONArray(), new String[]{} }, + {"{\"k0\":\"v0\"}", new ArrayList(0), new String[]{} },//17 + + //simple json, valid/invalid keys + {"{\"k0\":\"v0\"}", "k0", new String[]{"k0"} }, + {"{\"k0\":\"v0\"}", "v0", new String[]{} }, + {"{\"k0\":\"v0\"}", "k0.k1", new String[]{} }, + {"{\"k0\":\"v0\"}", "k1.k0", new String[]{} }, + {"{\"k0\":null}", "k0", new String[]{"k0"} }, + {"{\"k0\":null}", null, new String[]{} },//23 + + //key with dot char + {"{\"k0.k1\":\"v0\"}", "k0", new String[]{} }, + {"{\"k0.k1\":\"v0\"}", "k1", new String[]{} }, + {"{\"k0.k1\":\"v0\"}", "k0.k1", new String[]{} }, + + // key with dot ambiguity + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0", new String[]{"k0"} }, + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k1", new String[]{} }, + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0.k1", new String[]{"k0.k1"} }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1", new String[]{"k0.k1"} },//30 + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1.k2", new String[]{"k0.k1.k2"} }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k1.k2", new String[]{} }, + {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k0", new String[]{"k0"} }, + {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k1.k2", new String[]{"k1.k2"} }, + + //ignore non-existent keys but keep good keys + {"{\"k0\":\"v0\",\"k1\":\"v1\"}", new String[]{"k0","k2"}, new String[]{"k0"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k2"}, new String[]{"k0"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2"}, new String[]{"k0", "k1.k2"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2.k3"}, new String[]{"k0"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2","k1"}, new String[]{"k0","k1","k1.k2"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k0.k2"}, new String[]{"k0","k1"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k2"}, new String[]{"k0","k1"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2"}, new String[]{"k1.k2"} }, + + //arrays - key inside array treated as child + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0", new String[]{"k0"} }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", new String[]{"k0.k1"} }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", new String[]{"k0.k1.k2"} }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1.k2", new String[]{"k0.k1.k2", "k0.k1.k2"} }, + }); + } + + @Test + public void test() throws ParseException + { + JSONObject objectToSearch = jsonToSearch != null ? (JSONObject) JSONValue.parseWithException(jsonToSearch) : null; + PathLocator f = switchKeyToRemove(); + List found = f.find(objectToSearch); + assertEquals(Arrays.asList(expectedFound), found); + } + + private PathLocator switchKeyToRemove() + { + long m = System.currentTimeMillis(); + if (keysToFind == null && m % 4 == 0) + { + System.out.println("cast to String"); + return new PathLocator((String)null); + } + else if (keysToFind == null && m % 4 == 1) + { + System.out.println("cast to String[]"); + return new PathLocator((String[])null); + } + else if (keysToFind == null && m % 4 == 2) + { + System.out.println("cast to JSONArray"); + return new PathLocator((JSONArray)null); + } + else if (keysToFind == null && m % 4 == 3) + { + System.out.println("cast to List"); + return new PathLocator((List)null); + } + else if (keysToFind instanceof String) + { + return new PathLocator((String) keysToFind); + } + else if (keysToFind instanceof String[]) + { + return new PathLocator((String[]) keysToFind); + } + else if (keysToFind instanceof JSONArray) + { + return new PathLocator((JSONArray) keysToFind); + } + else if (keysToFind instanceof List) + { + return new PathLocator((List) keysToFind); + } + else + { + throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + } + } +} \ No newline at end of file diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java new file mode 100755 index 00000000..51d9c813 --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java @@ -0,0 +1,136 @@ +package net.minidev.json.test.actions; + +import net.minidev.json.actions.PathRemover; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.parser.ParseException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * Tests {@link PathRemover} + * + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class PathRemoverTest +{ + private String jsonToClean; + private Object keyToRemove; + private String expectedJson; + + public PathRemoverTest(String jsonToClean, Object keyToRemove, String expectedJson) + { + this.jsonToClean = jsonToClean; + this.keyToRemove = keyToRemove; + this.expectedJson = expectedJson; + } + + @Parameterized.Parameters + public static Collection params() + { + return Arrays.asList(new Object[][]{ + + {null, "key", null }, // null json + {"{}", "key", "{}" }, // empty json + {"{\"first\": null}", null, "{\"first\": null}" }, // null key + {"{\"first\": null}", "", "{\"first\": null}" }, // empty string key + {"{\"first\": null}", new String[]{}, "{\"first\": null}" }, // empty string array key + {"{\"first\": null}", new JSONArray(), "{\"first\": null}" }, // empty json array key + {"{\"first\": null}", new ArrayList(0), "{\"first\": null}" }, // empty list key + {"{\"first\": null}", "first", "{}" }, // remove root key + {"{\"first.f1\": null}", "first.f1", "{}" }, // key with dot + {"{\"first.f1\": \"withDot\", \"first\":{\"f1\": null}}", "first.f1", "{\"first\":{}}" }, // key with dot ambiguity + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{}}}}" }, // nested object remove single leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "notfound", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, // nested object key does not exist + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{\"name\":\"me\"}}}}"}, // nested object remove first leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.name", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, // nested object remove last leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3", "{\"first\":{\"f2\":{}}}" }, // nested object remove intermediate node + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first", "{}" }, // nested object remove root + {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2.id", "{\"first\":{\"f2\":[[1,{},3],4]}}" }, // double nested array remove leaf + {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2", "{\"first\":{}}" }, // double nested array remove array + {"{\"first\":[[1,{\"id\":\"id1\"},3],4]}", "first", "{}" }, // double nested array remove root + + //arrays + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", "{\"k0\":{}}" }, // value is array + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{},3,4]}}" }, // full path into array object + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.3" , "{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}" }, // full path into array primitive + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{},{},3,4]}}" }, // full path into array with identical items + + // composite json remove all roots + {"{\"first\": {\"f2\":{\"id\":\"id1\"}}, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}", + (JSONArray) JSONValue.parse("[\"first\",\"second\",\"third\",\"id\"]"), + "{}" }, + // composite json remove all leaves + {"{\"first\": {\"f2\":{\"id\":\"id1\"}}, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}", + (List) Arrays.asList("first.f2.id", "second.k1.id", "second.id", "third", "id"), + "{\"first\": {\"f2\":{}}, \"second\": [{\"k1\":{}}, 4, 5, 6, {}]}" }, + + }); + } + + @Test + public void test() throws ParseException + { + JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; + JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson): null; + PathRemover cl = switchKeyToRemove(); + cl.remove(objectToClean); + assertEquals(expectedObject, objectToClean); + } + + private PathRemover switchKeyToRemove() + { + long m = System.currentTimeMillis(); + if (keyToRemove == null && m % 4 == 0) + { + System.out.println("cast to String"); + return new PathRemover((String)null); + } + else if (keyToRemove == null && m % 4 == 1) + { + System.out.println("cast to String[]"); + return new PathRemover((String[])null); + } + else if (keyToRemove == null && m % 4 == 2) + { + System.out.println("cast to JSONArray"); + return new PathRemover((JSONArray)null); + } + else if (keyToRemove == null && m % 4 == 3) + { + System.out.println("cast to List"); + return new PathRemover((List)null); + } + else if (keyToRemove instanceof String) + { + return new PathRemover((String)keyToRemove); + } + else if (keyToRemove instanceof String[]) + { + return new PathRemover((String[])keyToRemove); + } + else if (keyToRemove instanceof JSONArray) + { + return new PathRemover((JSONArray)keyToRemove); + } + else if (keyToRemove instanceof List) + { + return new PathRemover((List)keyToRemove); + } + else + { + throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + } + } + +} diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java new file mode 100755 index 00000000..3c9c13de --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java @@ -0,0 +1,232 @@ +package net.minidev.json.test.actions; + +import net.minidev.json.actions.PathReplicator; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class PathReplicatorTest +{ + private String jsonSource; + private Object pathsToCopy; + private Object expected; + + public PathReplicatorTest(String jsonSource, Object pathsToCopy, Object expected) + { + this.jsonSource = jsonSource; + this.pathsToCopy = pathsToCopy; + this.expected = expected; + } + + @Parameterized.Parameters + public static Collection params() + { + return Arrays.asList(new Object[][]{ + + //nulls, bad/empty keys + {null, null, null }, + {null, "", null }, + {null, "k1", null }, + {null, new String[]{}, null }, + {null, new JSONArray(), null }, + {null, new ArrayList(0), null },//5 + + //empty json, bad/empty keys + {"{}", null, "{}" }, + {"{}", "", "{}" }, + {"{}", "k1", "{}" }, + {"{}", new String[]{}, "{}" }, + {"{}", new JSONArray(), "{}" }, + {"{}", new ArrayList(0), "{}" },//11 + + //simple json, bad/empty keys + {"{\"k0\":\"v0\"}", null, "{}" }, + {"{\"k0\":\"v0\"}", "", "{}" }, + {"{\"k0\":\"v0\"}", "k1", "{}" }, + {"{\"k0\":\"v0\"}", new String[]{}, "{}" }, + {"{\"k0\":\"v0\"}", new JSONArray(), "{}" }, + {"{\"k0\":\"v0\"}", new ArrayList(0), "{}" },//17 + + //simple json, valid/invalid keys + {"{\"k0\":\"v0\"}", "k0", "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\"}", "v0", "{}" }, + {"{\"k0\":\"v0\"}", "k0.k1", "{}" },//20 + {"{\"k0\":\"v0\"}", "k1.k0", "{}" }, + {"{\"k0\":null}", "k0", "{\"k0\":null}" }, + {"{\"k0\":null}", "v0", "{}" }, + + //key with dot char + {"{\"k0.k1\":\"v0\"}", "k0", "{}" }, + {"{\"k0.k1\":\"v0\"}", "k1", "{}" }, + {"{\"k0.k1\":\"v0\"}", "k0.k1", "{}" }, + + // key with dot ambiguity + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0", "{\"k0\":{}}" }, + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k1", "{}" }, + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0.k1", "{\"k0\":{\"k1\":null}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1", "{\"k0\":{\"k1\":{}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1.k2", "{\"k0\":{\"k1\":{\"k2\":null}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k1.k2", "{}" }, + {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k0", "{\"k0\":{}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k1.k2", "{\"k1\":{\"k2\":\"v2\"}}}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2.k3.k4", "{}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2.k3", "{}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2", "{\"k0\":{\"k2\":{}}}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0", "{\"k0\":{}}" },//38 + + //ignore non-existent keys but keep good keys + {"{\"k0\":\"v0\",\"k1\":\"v1\"}", new String[]{"k0","k2"}, "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k2"}, "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2"}, "{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k0.k2"}, "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2","k1"}, "{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1"}, "{\"k0\":\"v0\",\"k1\":{}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k2"}, "{\"k0\":\"v0\",\"k1\":{}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2"}, "{\"k1\":{\"k2\":\"v2\"}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2.k3"}, "{}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0.k1.k2"}, "{}" },//48 + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k0"}, "{}" }, + + //arrays - key inside array treated as child + {"{\"k0\":{\"k1\":[1,2,3,4]}}", "k0", "{\"k0\":{}}" }, + {"{\"k0\":{\"k1\":[1,2,3,4]}}", "k0.k1", "{\"k0\":{\"k1\":[1,2,3,4]}}" }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0", "{\"k0\":{}}" }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", "{\"k0\":{\"k1\":[1,{},3,4]}}" }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1", "{\"k0\":{\"k1\":[{},{}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":\"v4\"}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":\"v4\"}]}}", "k0.k3.k4", "{\"k0\":{\"k3\":[{\"k4\":\"v4\"}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", "k0.k3.k4", "{\"k0\":{\"k3\":[{\"k4\":{}}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", "k0.k3.k4.k5", "{\"k0\":{\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", new String[]{"k0.k1", "k0.k3"}, "{\"k0\":{\"k3\":[{}],\"k1\":[{}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", new String[]{"k0.k1", "k0.k3.k4.k5"}, "{\"k0\":{\"k3\":[{\"k4\":{\"k5\":\"v5\"}}],\"k1\":[{}]}}" }, + }); + } + + @Test + public void test() throws Exception + { + JSONObject objectSource = jsonSource != null ? (JSONObject) JSONValue.parseWithException(jsonSource) :null; + PathReplicator copier = switchKeyToCopy(); + JSONObject copied = copier.replicate(objectSource); + JSONObject expectedObj = expected != null ? (JSONObject) JSONValue.parseWithException((String) expected) : null; + assertEquals(expectedObj, copied); + } + + @Test + public void test2() throws Exception + { + JSONObject objectSource = jsonSource != null ? (JSONObject) JSONValue.parseWithException(jsonSource) :null; + PathReplicator copier = switchKeyToCopy2(); + JSONObject copied = copier.replicate(objectSource); + JSONObject expectedObj = expected != null ? (JSONObject) JSONValue.parseWithException((String) expected) : null; + assertEquals(expectedObj, copied); + } + + private PathReplicator switchKeyToCopy() + { + long m = System.currentTimeMillis(); + if (pathsToCopy == null && m % 4 == 0) + { + System.out.println("cast to String"); + return new PathReplicator((String)null); + } + else if (pathsToCopy == null && m % 4 == 1) + { + System.out.println("cast to String[]"); + return new PathReplicator((String[])null); + } + else if (pathsToCopy == null && m % 4 == 2) + { + System.out.println("cast to JSONArray"); + return new PathReplicator((JSONArray)null); + } + else if (pathsToCopy == null && m % 4 == 3) + { + System.out.println("cast to List"); + return new PathReplicator((List)null); + } + else if (pathsToCopy instanceof String) + { + return new PathReplicator((String) pathsToCopy); + } + else if (pathsToCopy instanceof String[]) + { + return new PathReplicator((String[]) pathsToCopy); + } + else if (pathsToCopy instanceof JSONArray) + { + return new PathReplicator((JSONArray) pathsToCopy); + } + else if (pathsToCopy instanceof List) + { + return new PathReplicator((List) pathsToCopy); + } + else + { + throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + } + } + + private PathReplicator switchKeyToCopy2() + { + long m = System.currentTimeMillis(); + if (pathsToCopy == null && m % 4 == 0) + { + System.out.println("cast to String"); + return new PathReplicator((String)null); + } + else if (pathsToCopy == null && m % 4 == 1) + { + System.out.println("cast to String[]"); + return new PathReplicator((String[])null); + } + else if (pathsToCopy == null && m % 4 == 2) + { + System.out.println("cast to JSONArray"); + return new PathReplicator((JSONArray)null); + } + else if (pathsToCopy == null && m % 4 == 3) + { + System.out.println("cast to List"); + return new PathReplicator((List)null); + } + else if (pathsToCopy instanceof String) + { + return new PathReplicator((String) pathsToCopy); + } + else if (pathsToCopy instanceof String[]) + { + return new PathReplicator((String[]) pathsToCopy); + } + else if (pathsToCopy instanceof JSONArray) + { + return new PathReplicator((JSONArray) pathsToCopy); + } + else if (pathsToCopy instanceof List) + { + return new PathReplicator((List) pathsToCopy); + } + else + { + throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + } + } + +} \ No newline at end of file diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java new file mode 100755 index 00000000..c6cee591 --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java @@ -0,0 +1,168 @@ +package net.minidev.json.test.actions; + +import net.minidev.json.actions.PathsRetainer; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.parser.ParseException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class PathsRetainerTest +{ + private String jsonToReduce; + private Object keyToKeep; + private String expectedReducedJson; + + public PathsRetainerTest(String jsonToReduce, Object keyToKeep, String expectedReducedJson) + { + this.jsonToReduce = jsonToReduce; + this.keyToKeep = keyToKeep; + this.expectedReducedJson = expectedReducedJson; + } + + @Parameterized.Parameters + public static Collection params() + { + return Arrays.asList(new Object[][]{ + + //nulls, bad/empty keys + {null, null, null }, + {null, "", null }, + {null, "k1", null }, + {null, new String[]{}, null }, + {null, new JSONArray(), null }, + {null, new ArrayList(0), null },//5 + + //empty json, bad/empty keys + {"{}", null, "{}" }, + {"{}", "", "{}" }, + {"{}", "k1", "{}" }, + {"{}", new String[]{}, "{}" }, + {"{}", new JSONArray(), "{}" }, + {"{}", new ArrayList(0), "{}" },//11 + + //simple json, bad/empty keys + {"{\"k0\":\"v0\"}", null, "{}" }, + {"{\"k0\":\"v0\"}", "", "{}" }, + {"{\"k0\":\"v0\"}", "k1", "{}" }, + {"{\"k0\":\"v0\"}", new String[]{}, "{}" }, + {"{\"k0\":\"v0\"}", new JSONArray(), "{}" }, + {"{\"k0\":\"v0\"}", new ArrayList(0), "{}" },//17 + + //simple json, valid/invalid keys + {"{\"k0\":\"v0\"}", "k0", "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\"}", "v0", "{}" }, + {"{\"k0\":\"v0\"}", "k0.k1", "{}" }, + {"{\"k0\":\"v0\"}", "k1.k0", "{}" }, + {"{\"k0\":null}", "k0", "{\"k0\":null}" }, + {"{\"k0\":null}", "v0", "{}" },//23 + + //key with dot char + {"{\"k0.k1\":\"v0\"}", "k0", "{}" }, + {"{\"k0.k1\":\"v0\"}", "k1", "{}" }, + {"{\"k0.k1\":\"v0\"}", "k0.k1", "{}" }, + + // key with dot ambiguity + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0", "{\"k0\":{}}" },//27 + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k1", "{}" }, + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0.k1", "{\"k0\":{\"k1\":null}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1", "{\"k0\":{\"k1\":{}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1.k2", "{\"k0\":{\"k1\":{\"k2\":null}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k1.k2", "{}" }, + {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k0", "{\"k0\":{}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k1.k2", "{\"k1\":{\"k2\":\"v2\"}}}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2.k3.k4", "{}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2.k3", "{}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2", "{\"k0\":{\"k2\":{}}}" }, + {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0", "{\"k0\":{}}" }, + + //ignore non-existent keys but keep good keys + {"{\"k0\":\"v0\",\"k1\":\"v1\"}", new String[]{"k0","k2"}, "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k2"}, "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2"}, "{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k0.k2"}, "{\"k0\":\"v0\"}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2","k1"}, "{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1"}, "{\"k0\":\"v0\",\"k1\":{}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k2"}, "{\"k0\":\"v0\",\"k1\":{}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2"}, "{\"k1\":{\"k2\":\"v2\"}}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2.k3"}, "{}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0.k1.k2"}, "{}" }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k0"}, "{}" }, + + //arrays - key inside array treated as child + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0", "{\"k0\":{}}" }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", "{\"k0\":{\"k1\":[1,{},3,4]}}" }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1", "{\"k0\":{\"k1\":[{},{}]}}" }, + {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}" }, + }); + } + + @Test + public void test() throws ParseException + { + JSONObject objectToReduce = jsonToReduce != null ? (JSONObject) JSONValue.parseWithException(jsonToReduce) :null; + JSONObject expectedReducedObj = expectedReducedJson != null ? (JSONObject) JSONValue.parseWithException(expectedReducedJson):null; + PathsRetainer reducer = switchKeyToRemove(); + JSONObject reducedObj = reducer.retain(objectToReduce); + assertEquals(expectedReducedObj, reducedObj); + } + + private PathsRetainer switchKeyToRemove() + { + long m = System.currentTimeMillis(); + if (keyToKeep == null && m % 4 == 0) + { + System.out.println("cast to String"); + return new PathsRetainer((String)null); + } + else if (keyToKeep == null && m % 4 == 1) + { + System.out.println("cast to String[]"); + return new PathsRetainer((String[])null); + } + else if (keyToKeep == null && m % 4 == 2) + { + System.out.println("cast to JSONArray"); + return new PathsRetainer((JSONArray)null); + } + else if (keyToKeep == null && m % 4 == 3) + { + System.out.println("cast to List"); + return new PathsRetainer((List)null); + } + else if (keyToKeep instanceof String) + { + return new PathsRetainer((String) keyToKeep); + } + else if (keyToKeep instanceof String[]) + { + return new PathsRetainer((String[]) keyToKeep); + } + else if (keyToKeep instanceof JSONArray) + { + return new PathsRetainer((JSONArray) keyToKeep); + } + else if (keyToKeep instanceof List) + { + return new PathsRetainer((List) keyToKeep); + } + else + { + throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + } + } +} \ No newline at end of file From 2d42e34b62f63e99cf7b7059cf7ecc3ab690bf0e Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Tue, 5 Apr 2016 22:40:21 +0300 Subject: [PATCH 02/18] gitignore intellij idea files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 286679a2..8c0b7388 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ json-smart/target/ *.classpath *.project *.prefs +*.iml +.idea \ No newline at end of file From 909c53c3e5e1c38620ab576f8b9e8ff6db57e0ee Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Mon, 18 Apr 2016 00:25:43 +0300 Subject: [PATCH 03/18] rename actions --- .../src/main/java/net/minidev/json/actions/PathRemover.java | 4 ++-- .../src/main/java/net/minidev/json/actions/PathsRetainer.java | 4 ++-- .../traverse/{RemoveAction.java => RemovePathsAction.java} | 4 ++-- .../traverse/{RetainAction.java => RetainPathsAction.java} | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) rename json-smart/src/main/java/net/minidev/json/actions/traverse/{RemoveAction.java => RemovePathsAction.java} (93%) rename json-smart/src/main/java/net/minidev/json/actions/traverse/{RetainAction.java => RetainPathsAction.java} (95%) diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java index fb3e1bd8..1a2568ea 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java @@ -3,7 +3,7 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.RemoveAction; +import net.minidev.json.actions.traverse.RemovePathsAction; import net.minidev.json.actions.traverse.TraverseAction; import java.util.ArrayList; @@ -66,7 +66,7 @@ public PathRemover(String... pathsToRemove) public JSONObject remove(JSONObject objectToClean) { - TraverseAction strategy = new RemoveAction(this.pathsToRemove); + TraverseAction strategy = new RemovePathsAction(this.pathsToRemove); JSONTraverser traversal = new JSONTraverser(strategy); traversal.traverse(objectToClean); return (JSONObject) strategy.result(); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java index 6dc146dd..7a73f5e3 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java @@ -2,7 +2,7 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; -import net.minidev.json.actions.traverse.RetainAction; +import net.minidev.json.actions.traverse.RetainPathsAction; import net.minidev.json.actions.traverse.JSONTraverser; import net.minidev.json.actions.traverse.LocatePathsAction; import net.minidev.json.actions.traverse.TraverseAction; @@ -77,7 +77,7 @@ public JSONObject retain(JSONObject object) List realPathsToRetain = (List) locateAction.result(); //now reduce the object using only existing paths - TraverseAction reduce = new RetainAction(realPathsToRetain); + TraverseAction reduce = new RetainPathsAction(realPathsToRetain); JSONTraverser t2 = new JSONTraverser(reduce); t2.traverse(object); return (JSONObject) reduce.result(); diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsAction.java similarity index 93% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java rename to json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsAction.java index 00d9f8ef..0b41d8e9 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsAction.java @@ -19,12 +19,12 @@ * @author adoneitan@gmail.com * */ -public class RemoveAction implements TraverseAction +public class RemovePathsAction implements TraverseAction { protected JSONObject result; protected List pathsToRemove; - public RemoveAction(List pathsToRemove) + public RemovePathsAction(List pathsToRemove) { this.pathsToRemove = pathsToRemove; } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsAction.java similarity index 95% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java rename to json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsAction.java index 1234ff65..49a9361e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsAction.java @@ -23,12 +23,12 @@ * @author adoneitan@gmail.com * */ -public class RetainAction implements TraverseAction +public class RetainPathsAction implements TraverseAction { protected JSONObject result; protected List pathsToRetain; - public RetainAction(List pathsToRetain) + public RetainPathsAction(List pathsToRetain) { this.pathsToRetain = new ArrayList(pathsToRetain); } From 38f9a537bb4d7a93f4b63d21b4703de1f0779f05 Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Mon, 18 Apr 2016 00:26:07 +0300 Subject: [PATCH 04/18] add ElementRemover --- .../minidev/json/actions/ElementRemover.java | 51 +++++++++ .../traverse/RemoveElementsAction.java | 87 ++++++++++++++ .../json/test/actions/ElementRemoverTest.java | 106 ++++++++++++++++++ 3 files changed, 244 insertions(+) create mode 100755 json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java create mode 100755 json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java new file mode 100755 index 00000000..06db5a8c --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java @@ -0,0 +1,51 @@ +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.RemoveElementsAction; +import net.minidev.json.actions.traverse.TraverseAction; + +import java.util.*; + +/** + * Removes key:value elements from every node of a {@link JSONObject} matching the list of user-specified elements. + *

+ * An element to remove must be specified as a key:value pair + *

+ * Usage Example: + *

+ * To remove the element k2:v2 from the {@link JSONObject} {k0:{k2:v2, k3:v3}, k1:{k2:v2, k4:v4}} use the remover like so: + *

+ * PathRemover pr = new PathRemover("k2.v2");
+ * JSONObject cleanObject = pr.remove(new JSONObject(...));
+ * 
+ * The resulting object 'cleanObject' would be {k0:{k3:v3}, k1:{k4:v4}} + *

+ * See unit tests for more examples + * + * @author adoneitan@gmail.com + * + */ +public class ElementRemover +{ + private Map elementsToRemove; + + public ElementRemover(Map elementsToRemove) + { + this.elementsToRemove = elementsToRemove == null ? Collections.emptyMap() : elementsToRemove; + } + + public ElementRemover(JSONObject elementsToRemove) + { + this.elementsToRemove = elementsToRemove == null ? Collections.emptyMap() : elementsToRemove; + } + + public JSONObject remove(JSONObject objectToClean) + { + TraverseAction strategy = new RemoveElementsAction(this.elementsToRemove); + JSONTraverser traversal = new JSONTraverser(strategy); + traversal.traverse(objectToClean); + return (JSONObject) strategy.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java new file mode 100755 index 00000000..948ffac1 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java @@ -0,0 +1,87 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONObject; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/** + * Removes key:value elements from a {@link JSONObject}. + *

+ * An element is not removed from the user-specified list once its processing is over, + * because it may appear in more than one node. + *

+ * See package-info for more details + *

+ * See unit tests for examples + * + * @author adoneitan@gmail.com + * + */ +public class RemoveElementsAction implements TraverseAction +{ + protected JSONObject result; + protected final Map elementsToRemove; + protected final boolean allowDotChar; + + public RemoveElementsAction(Map elementsToRemove, boolean allowDotChar) + { + this.elementsToRemove = elementsToRemove; + this.allowDotChar = allowDotChar; + } + + public RemoveElementsAction(Map elementsToRemove) + { + this(elementsToRemove, false); + } + + @Override + public boolean handleStart(JSONObject object) + { + result = object; + return object != null && elementsToRemove != null && elementsToRemove.size() > 0; + } + + @Override + public boolean handleDotChar() { + return allowDotChar; + } + + @Override + public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + { + if (elementsToRemove.entrySet().contains(entry)) + { + it.remove(); + } + return false; + } + + @Override + public boolean handleNext() + { + //must traverse the whole object + return true; + } + + @Override + public boolean handleJSONObjectChild() { + return true; + } + + @Override + public boolean handleJSONArrayChild() { + return true; + } + + @Override + public void handleEnd() { + //nothing to do + } + + @Override + public Object result() { + return result; + } +} diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java new file mode 100755 index 00000000..327fa2d1 --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java @@ -0,0 +1,106 @@ +package net.minidev.json.test.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.actions.ElementRemover; +import net.minidev.json.parser.ParseException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * Tests {@link ElementRemover} + * + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class ElementRemoverTest +{ + private String jsonToClean; + private String elementsToRemove; + private String expectedJson; + + public ElementRemoverTest(String jsonToClean, String elementsToRemove, String expectedJson) + { + this.jsonToClean = jsonToClean; + this.elementsToRemove = elementsToRemove; + this.expectedJson = expectedJson; + } + + @Parameterized.Parameters + public static Collection params() + { + return Arrays.asList(new Object[][]{ + + {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", null, "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, + {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{}", "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, + {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k0\":\"v2\"}", "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, + {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k2\":\"v2\"}", "{\"k0\":{},\"k1\":{\"k3\":\"v3\"}}"}, + {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k0\":{\"k2\":\"v2\"}}", "{\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, + {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k2\":\"v2\",\"k3\":\"v3\"}", "{\"k0\":{},\"k1\":{}}"}, + {"{\"k0\":{}}", "{}", "{\"k0\":{}}"}, + }); + } + + @Test + public void test() throws ParseException + { + JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; + JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson): null; + JSONObject toRemove = elementsToRemove != null ? (JSONObject) JSONValue.parseWithException(elementsToRemove): null; + ElementRemover er = new ElementRemover(toRemove); + er.remove(objectToClean); + assertEquals(expectedObject, objectToClean); + } + +// private ElementRemover switchKeyToRemove() +// { +// long m = System.currentTimeMillis(); +// if (elementsToRemove == null && m % 4 == 0) +// { +// System.out.println("cast to String"); +// return new ElementRemover((String)null); +// } +// else if (elementsToRemove == null && m % 4 == 1) +// { +// System.out.println("cast to String[]"); +// return new ElementRemover((String[])null); +// } +// else if (elementsToRemove == null && m % 4 == 2) +// { +// System.out.println("cast to JSONArray"); +// return new ElementRemover((JSONArray)null); +// } +// else if (elementsToRemove == null && m % 4 == 3) +// { +// System.out.println("cast to List"); +// return new ElementRemover((List)null); +// } +// else if (elementsToRemove instanceof String) +// { +// return new ElementRemover((String) elementsToRemove); +// } +// else if (elementsToRemove instanceof String[]) +// { +// return new ElementRemover((String[]) elementsToRemove); +// } +// else if (elementsToRemove instanceof JSONArray) +// { +// return new ElementRemover((JSONArray) elementsToRemove); +// } +// else if (elementsToRemove instanceof List) +// { +// return new ElementRemover((List) elementsToRemove); +// } +// else +// { +// throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); +// } +// } + +} From 92adc26e9726ffc18a05b321a90a15d315816de7 Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Mon, 6 Jun 2016 15:40:45 +0300 Subject: [PATCH 05/18] enhance traversal API --- .../minidev/json/actions/ElementRemover.java | 7 +- .../net/minidev/json/actions/PathLocator.java | 16 ++- .../net/minidev/json/actions/PathRemover.java | 6 +- .../minidev/json/actions/PathsRetainer.java | 26 +++-- .../actions/navigate/CopyPathsAction.java | 11 +- .../json/actions/navigate/JSONNavigator.java | 16 +-- .../json/actions/navigate/NavigateAction.java | 11 +- .../json/actions/path/DotDelimiter.java | 23 ++++ .../actions/{navigate => path}/JSONPath.java | 43 +++---- .../json/actions/path/PathDelimiter.java | 43 +++++++ .../actions/traverse/JSONTraverseAction.java | 15 +++ .../json/actions/traverse/JSONTraverser.java | 66 +---------- .../actions/traverse/KeysPrintAction.java | 68 +++++++++++ ...Action.java => LocatePathsJSONAction.java} | 52 ++++++--- ...ion.java => RemoveElementsJSONAction.java} | 44 ++++---- ...Action.java => RemovePathsJsonAction.java} | 42 +++---- ...Action.java => RetainPathsJsonAction.java} | 66 ++++++----- .../json/actions/traverse/TraverseAction.java | 62 ---------- .../actions/traverse/TreeTraverseAction.java | 74 ++++++++++++ .../json/actions/traverse/TreeTraverser.java | 106 ++++++++++++++++++ .../json/actions/traverse/package-info.java | 8 +- .../actions/traverse/KeysPrintActionTest.java | 43 +++++++ .../json/test/actions/JSONPathTest.java | 12 +- .../json/test/actions/PathLocatorTest.java | 24 ++-- .../json/test/actions/PathRemoverTest.java | 4 +- .../json/test/actions/PathsRetainerTest.java | 9 +- 26 files changed, 601 insertions(+), 296 deletions(-) create mode 100644 json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java rename json-smart/src/main/java/net/minidev/json/actions/{navigate => path}/JSONPath.java (79%) create mode 100644 json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java create mode 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java rename json-smart/src/main/java/net/minidev/json/actions/traverse/{LocatePathsAction.java => LocatePathsJSONAction.java} (57%) rename json-smart/src/main/java/net/minidev/json/actions/traverse/{RemoveElementsAction.java => RemoveElementsJSONAction.java} (55%) rename json-smart/src/main/java/net/minidev/json/actions/traverse/{RemovePathsAction.java => RemovePathsJsonAction.java} (56%) rename json-smart/src/main/java/net/minidev/json/actions/traverse/{RetainPathsAction.java => RetainPathsJsonAction.java} (50%) delete mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java create mode 100644 json-smart/src/test/java/net/minidev/json/actions/traverse/KeysPrintActionTest.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java index 06db5a8c..c501b58e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java +++ b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java @@ -1,10 +1,9 @@ package net.minidev.json.actions; -import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.RemoveElementsAction; -import net.minidev.json.actions.traverse.TraverseAction; +import net.minidev.json.actions.traverse.RemoveElementsJsonAction; +import net.minidev.json.actions.traverse.JSONTraverseAction; import java.util.*; @@ -43,7 +42,7 @@ public ElementRemover(JSONObject elementsToRemove) public JSONObject remove(JSONObject objectToClean) { - TraverseAction strategy = new RemoveElementsAction(this.elementsToRemove); + JSONTraverseAction strategy = new RemoveElementsJsonAction(this.elementsToRemove); JSONTraverser traversal = new JSONTraverser(strategy); traversal.traverse(objectToClean); return (JSONObject) strategy.result(); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java index 1e80a1f1..e66eea55 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java @@ -2,9 +2,11 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.PathDelimiter; import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.LocatePathsAction; -import net.minidev.json.actions.traverse.TraverseAction; +import net.minidev.json.actions.traverse.LocatePathsJsonAction; +import net.minidev.json.actions.traverse.JSONTraverseAction; import java.util.ArrayList; import java.util.Arrays; @@ -29,6 +31,7 @@ public class PathLocator { private List pathsToFind; + private PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); public PathLocator(JSONArray pathsToFind) { @@ -56,9 +59,14 @@ public PathLocator(String... pathsToFind) Collections.emptyList() : Arrays.asList(pathsToFind); } - public List find(JSONObject object) + public PathLocator with(PathDelimiter pathDelimiter) { + this.pathDelimiter = pathDelimiter; + return this; + } + + public List locate(JSONObject object) { - TraverseAction action = new LocatePathsAction(this.pathsToFind); + JSONTraverseAction action = new LocatePathsJsonAction(this.pathsToFind, pathDelimiter); JSONTraverser traversal = new JSONTraverser(action); traversal.traverse(object); return (List) action.result(); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java index 1a2568ea..f2532da4 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java @@ -3,8 +3,8 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.RemovePathsAction; -import net.minidev.json.actions.traverse.TraverseAction; +import net.minidev.json.actions.traverse.RemovePathsJsonAction; +import net.minidev.json.actions.traverse.JSONTraverseAction; import java.util.ArrayList; import java.util.Arrays; @@ -66,7 +66,7 @@ public PathRemover(String... pathsToRemove) public JSONObject remove(JSONObject objectToClean) { - TraverseAction strategy = new RemovePathsAction(this.pathsToRemove); + JSONTraverseAction strategy = new RemovePathsJsonAction(this.pathsToRemove); JSONTraverser traversal = new JSONTraverser(strategy); traversal.traverse(objectToClean); return (JSONObject) strategy.result(); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java index 7a73f5e3..7e256814 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java @@ -2,10 +2,12 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; -import net.minidev.json.actions.traverse.RetainPathsAction; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.PathDelimiter; +import net.minidev.json.actions.traverse.JSONTraverseAction; import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.LocatePathsAction; -import net.minidev.json.actions.traverse.TraverseAction; +import net.minidev.json.actions.traverse.LocatePathsJsonAction; +import net.minidev.json.actions.traverse.RetainPathsJsonAction; import java.util.Arrays; import java.util.Collections; @@ -34,6 +36,7 @@ public class PathsRetainer { protected List pathsToRetain; + private PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); public PathsRetainer(JSONArray pathsToRetain) { @@ -60,26 +63,31 @@ public PathsRetainer(String... pathsToRetain) this.pathsToRetain = pathsToRetain == null || pathsToRetain.length == 0 ? Collections.emptyList() : new LinkedList(Arrays.asList(pathsToRetain)); } + + public PathsRetainer with(PathDelimiter pathDelimiter) { + this.pathDelimiter = pathDelimiter; + return this; + } public JSONObject retain(JSONObject object) { /** * a path to retain which contains a path in the object, but is not itself a path in the object, - * will cause the sub-path to be retain although it shouldn't: + * will cause the sub-path to be retained although it shouldn't: * object = {k0:v0} retain = {k0.k1} * so the false path to retain has to be removed from the pathsToRetain list. * - * The {@link LocatePathsAction} returns only paths which exist in the object. + * The {@link LocatePathsJsonAction} returns only paths which exist in the object. */ - TraverseAction locateAction = new LocatePathsAction(pathsToRetain); + JSONTraverseAction locateAction = new LocatePathsJsonAction(pathsToRetain, pathDelimiter); JSONTraverser t1 = new JSONTraverser(locateAction); t1.traverse(object); List realPathsToRetain = (List) locateAction.result(); //now reduce the object using only existing paths - TraverseAction reduce = new RetainPathsAction(realPathsToRetain); - JSONTraverser t2 = new JSONTraverser(reduce); + JSONTraverseAction retainer = new RetainPathsJsonAction(realPathsToRetain, pathDelimiter); + JSONTraverser t2 = new JSONTraverser(retainer); t2.traverse(object); - return (JSONObject) reduce.result(); + return (JSONObject) retainer.result(); } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java index e044167c..ba62fafd 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -2,6 +2,7 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.JSONPath; import java.util.Collection; import java.util.Stack; @@ -54,7 +55,7 @@ public boolean handleNavigationStart(JSONObject source, Collection paths } @Override - public boolean handleObjectStartAndRecur(JSONPath jp, JSONObject o) + public boolean handleJSONObject(JSONPath jp, JSONObject o) { //reached JSONObject node - instantiate it and recur handleNewNode(jp, new JSONObject()); @@ -73,7 +74,7 @@ else if (destNodeStack.peek() instanceof JSONArray) { } @Override - public boolean handleArrayStartAndRecur(JSONPath jp, JSONArray o) + public boolean handleJSONArrray(JSONPath jp, JSONArray o) { //reached JSONArray node - instantiate it and recur handleNewNode(jp, new JSONArray()); @@ -86,17 +87,17 @@ public void handlePrematureNavigatedBranchEnd(JSONPath jp, Object source) { } @Override - public void handleObjectLeaf(JSONPath jp, Object o) { + public void handleJSONObjectLeaf(JSONPath jp, Object o) { ((JSONObject) destNodeStack.peek()).put(jp.curr(), o); } @Override - public void handleArrayLeaf(int arrIndex, Object o) { + public void handleJSONArrayLeaf(int arrIndex, Object o) { ((JSONArray) destNodeStack.peek()).add(o); } @Override - public void handleArrayEnd(JSONPath jp) { + public void handleJSONArrayEnd(JSONPath jp) { destNodeStack.pop(); } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java index b5789af9..06da109f 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java @@ -2,6 +2,8 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.JSONPath; import java.util.Arrays; import java.util.Collections; @@ -80,7 +82,7 @@ public void nav(JSONObject object) throws Exception { if (path != null && !path.equals("") && action.handleNextPath(path)) { - JSONPath jp = new JSONPath(path); + JSONPath jp = new JSONPath(path, new DotDelimiter().withAcceptDelimiterInNodeName(true)); nav(object, jp); action.handlePathEnd(path); } @@ -115,12 +117,12 @@ private void nav(JSONObject source, JSONPath jp) // the specified path is illegal because it does not exist in the source. action.handlePrematureNavigatedBranchEnd(jp, source); } - else if (source.get(next) instanceof JSONObject && action.handleObjectStartAndRecur(jp, (JSONObject) source.get(next))) + else if (source.get(next) instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) source.get(next))) { //reached JSONObject node - handle it and recur into it nav((JSONObject) source.get(next), jp); } - else if (source.get(next) instanceof JSONArray && action.handleArrayStartAndRecur(jp, (JSONArray) source.get(next))) + else if (source.get(next) instanceof JSONArray && action.handleJSONArrray(jp, (JSONArray) source.get(next))) { //reached JSONArray node - handle it and recur into it nav((JSONArray) source.get(next), jp); @@ -134,7 +136,7 @@ else if (jp.hasNext()) else if (!jp.hasNext()) { //reached leaf in source and specified path is also at leaf -> handle it - action.handleObjectLeaf(jp, source.get(next)); + action.handleJSONObjectLeaf(jp, source.get(next)); } else { @@ -154,7 +156,7 @@ private void nav(JSONArray source, JSONPath jp) int arrIndex = 0; for (Object arrItem : source.toArray()) { - if (arrItem instanceof JSONObject && action.handleObjectStartAndRecur(jp, (JSONObject) arrItem)) + if (arrItem instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) arrItem)) { // clone the path so that for each JSONObject in the array, // the iterator continues from the same position in the path @@ -168,11 +170,11 @@ else if (arrItem instanceof JSONArray) else if (!jp.hasNext()) { //reached leaf - handle it - action.handleArrayLeaf(arrIndex, arrItem); + action.handleJSONArrayLeaf(arrIndex, arrItem); } arrIndex++; } - action.handleArrayEnd(jp); + action.handleJSONArrayEnd(jp); } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java index 72af94f7..eddf5438 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java @@ -2,6 +2,7 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.JSONPath; import java.util.Collection; @@ -53,13 +54,13 @@ public interface NavigateAction * called when an object node is encountered on the path * @return true if the navigator should navigate into the object */ - boolean handleObjectStartAndRecur(JSONPath jp, JSONObject sourceNode); + boolean handleJSONObject(JSONPath jp, JSONObject sourceNode); /** * called when an array node is encountered on the path * @return true if the navigator should navigate into the array */ - boolean handleArrayStartAndRecur(JSONPath jp, JSONArray sourceNode); + boolean handleJSONArrray(JSONPath jp, JSONArray sourceNode); /** * called when a leaf node is reached in a JSONObject. @@ -67,7 +68,7 @@ public interface NavigateAction * (it is not a JSONObject nor a JSONArray) * @param jp - the JsonPath pointing to the leaf */ - void handleObjectLeaf(JSONPath jp, Object value); + void handleJSONObjectLeaf(JSONPath jp, Object value); /** * called when a leaf in a JSONArray is reached. @@ -76,13 +77,13 @@ public interface NavigateAction * @param arrIndex - the index of the item in the JSONArray * @param arrItem - the item */ - void handleArrayLeaf(int arrIndex, Object arrItem); + void handleJSONArrayLeaf(int arrIndex, Object arrItem); /** * called after all the items of an array have been visited * @param jp - the JsonPath pointing to the array */ - void handleArrayEnd(JSONPath jp); + void handleJSONArrayEnd(JSONPath jp); /** * called after all the entries of a JSONObject have been visited diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java new file mode 100644 index 00000000..2ea2bc07 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java @@ -0,0 +1,23 @@ +package net.minidev.json.actions.path; + +/** + * Encapsulates the delimiter '.' of the path parts when the path is specified in n-gram format. + * For example: root.node1.node11.leaf + * + * @author adoneitan@gmail.com + * @since 31 May2016 + */ +public class DotDelimiter extends PathDelimiter +{ + protected static final char DELIM_CHAR = '.'; + + public DotDelimiter() + { + super(DELIM_CHAR); + } + + public String regex() + { + return "\\."; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java b/json-smart/src/main/java/net/minidev/json/actions/path/JSONPath.java similarity index 79% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java rename to json-smart/src/main/java/net/minidev/json/actions/path/JSONPath.java index 2bf589ff..2ab7d85a 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONPath.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/JSONPath.java @@ -1,4 +1,4 @@ -package net.minidev.json.actions.navigate; +package net.minidev.json.actions.path; import net.minidev.json.JSONObject; @@ -17,6 +17,7 @@ */ public class JSONPath { + protected enum Step {NONE, NEXT, PREV} protected final String path; protected List keys; @@ -25,12 +26,14 @@ protected enum Step {NONE, NEXT, PREV} protected Step lastStep; protected StringBuilder origin; protected StringBuilder remainder; + protected PathDelimiter delim; - public JSONPath(String path) + public JSONPath(String path, PathDelimiter delim) { + this.delim = delim; checkPath(path); this.path = path; - this.keys = Arrays.asList(path.split("\\.")); + this.keys = Arrays.asList(path.split(delim.regex())); reset(); } @@ -90,26 +93,26 @@ private void remainderDecrement() { if (length() == 1) remainder = new StringBuilder(""); - else if (remainder.indexOf(".") < 0) + else if (remainder.indexOf(delim.str()) < 0) remainder = new StringBuilder(""); else - remainder.delete(0, remainder.indexOf(".") + 1); + remainder.delete(0, remainder.indexOf(delim.str()) + 1); } private void originDecrement() { if (length() == 1) origin = new StringBuilder(""); - else if (origin.indexOf(".") < 0) + else if (origin.indexOf(delim.str()) < 0) origin = new StringBuilder(""); else - origin.delete(origin.lastIndexOf("."), origin.length()); + origin.delete(origin.lastIndexOf(delim.str()), origin.length()); } private void originIncrement() { if (origin.length() != 0) { - origin.append('.'); + origin.append(delim.chr()); } origin.append(currKey); } @@ -119,7 +122,7 @@ private void remainderIncrement(String prev) if (remainder.length() == 0) remainder = new StringBuilder(prev); else - remainder = new StringBuilder(prev).append('.').append(remainder); + remainder = new StringBuilder(prev).append(delim.chr()).append(remainder); } /** @@ -178,7 +181,7 @@ public String subPath(int firstIndex, int lastIndex) { sb.append(keys.get(i)); if (i < lastIndex) { - sb.append('.'); + sb.append(delim.chr()); } } sb.trimToSize(); @@ -189,14 +192,14 @@ private void checkPath(String path) { if (path == null || path.equals("")) throw new IllegalArgumentException("path cannot be null or empty"); - if (path.startsWith(".") || path.endsWith(".") || path.contains("src/main")) - throw new IllegalArgumentException("path cannot start or end with '.' or contain '..'"); + if (path.startsWith(delim.str()) || path.endsWith(delim.str()) || path.contains(delim.str() + delim.str())) + throw new IllegalArgumentException(String.format("path cannot start or end with %s or contain '%s%s'", delim.str(), delim.str(), delim.str())); } @Override public JSONPath clone() throws CloneNotSupportedException { - JSONPath cloned = new JSONPath(this.path); + JSONPath cloned = new JSONPath(this.path, this.delim); while (cloned.nextIndex() != this.nextIndex()) { cloned.next(); } @@ -218,12 +221,13 @@ public boolean equals(Object o) { JSONPath jsonPath = (JSONPath) o; return path().equals(jsonPath.path()) && - hasNext() == jsonPath.hasNext() && - hasPrev() == jsonPath.hasPrev() && - curr().equals(jsonPath.curr()) && - origin().equals(jsonPath.origin()) && - remainder().equals(jsonPath.remainder()) && - lastStep == jsonPath.lastStep; + hasNext() == jsonPath.hasNext() && + hasPrev() == jsonPath.hasPrev() && + curr().equals(jsonPath.curr()) && + origin().equals(jsonPath.origin()) && + remainder().equals(jsonPath.remainder()) && + lastStep == jsonPath.lastStep && + delim.equals(jsonPath.delim); } @@ -236,6 +240,7 @@ public int hashCode() { result = 31 * result + lastStep.hashCode(); result = 31 * result + origin.hashCode(); result = 31 * result + remainder.hashCode(); + result = 31 * result + delim.hashCode(); return result; } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java new file mode 100644 index 00000000..494406cb --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java @@ -0,0 +1,43 @@ +package net.minidev.json.actions.path; + +/** + * Encapsulates the delimiter of the path parts when given in n-gram format. + * + * @author adoneitan@gmail.com + * @since 31 May2016 + */ +public abstract class PathDelimiter +{ + protected char delimChar; + protected String delimStr; + protected boolean acceptDelimInKey; + + public PathDelimiter(char delim) + { + this.delimChar = delim; + this.delimStr = "" + delim; + } + + public PathDelimiter withAcceptDelimiterInNodeName(boolean acceptDelimInKey) { + this.acceptDelimInKey = acceptDelimInKey; + return this; + } + + public boolean accept(String key) + { + if (!acceptDelimInKey && key.contains(delimStr)) + return false; + return true; + } + + public String str() { + return delimStr; + } + + public char chr() { + return delimChar; + } + + public abstract String regex(); + +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java new file mode 100755 index 00000000..19aa6f20 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java @@ -0,0 +1,15 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +/** + * An interface for a processing action on the nodes of a {@link JSONObject} while traversing it. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public interface JSONTraverseAction extends TreeTraverseAction +{ +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java index ce543a20..2a6d62a0 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java @@ -3,14 +3,11 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; -import java.util.Iterator; -import java.util.Map; - /** * Traverses every node of a {@link JSONObject} *

* {@link JSONTraverser} accepts an action and provides callback hooks for it to act - * on the traversed nodes at each significant step. See {@link TraverseAction}. + * on the traversed nodes at each significant step. See {@link JSONTraverseAction}. *

* A key to the right of a dot is a direct child of a key to the left of a dot. * Keys with a dot in their name are not supported. @@ -20,65 +17,12 @@ * @author adoneitan@gmail.com * */ -public class JSONTraverser +public class JSONTraverser extends TreeTraverser { - private TraverseAction action; - - public JSONTraverser(TraverseAction action) - { - this.action = action; - } - - public void traverse(JSONObject object) - { - if (action.handleStart(object)){ - breadthFirst("", object); - } - action.handleEnd(); - } - - private void breadthFirst(String fullPathToObject, JSONObject jsonObject) - { - if (jsonObject == null || jsonObject.entrySet() == null) { - return; - } - Iterator> it = jsonObject.entrySet().iterator(); - while (it.hasNext() && action.handleNext()) - { - Map.Entry entry = it.next(); - if (entry.getKey().contains(".") && !action.handleDotChar()) - { - //a dot char '.' in the key is not supported by the action, abandon this path - continue; - } - String fullPathToEntry = "".equals(fullPathToObject) ? entry.getKey() : fullPathToObject + "." + entry.getKey(); - if (action.handleEntryAndIgnoreChildren(fullPathToEntry, it, entry)) - { - continue; - } - else if (entry.getValue() instanceof JSONObject && action.handleJSONObjectChild()) - { - breadthFirst(fullPathToEntry, (JSONObject) entry.getValue()); - } - else if (entry.getValue() instanceof JSONArray && action.handleJSONArrayChild()) - { - breadthFirst(fullPathToEntry, (JSONArray) entry.getValue()); - } - } - } + private JSONTraverseAction action; - private void breadthFirst(String fullPathToObject, JSONArray jsonArray) + public JSONTraverser(JSONTraverseAction action) { - for (Object arrItem : jsonArray.toArray()) - { - if (arrItem instanceof JSONObject) - { - breadthFirst(fullPathToObject, (JSONObject) arrItem); - } - else if (arrItem instanceof JSONArray) - { - breadthFirst(fullPathToObject, (JSONArray) arrItem); - } - } + super(action); } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java new file mode 100644 index 00000000..b3e8e993 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java @@ -0,0 +1,68 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.parser.ParseException; + +import java.util.Map; + +/** + * @author adoneitan@gmail.com + * @since 5/24/16. + */ +public class KeysPrintAction implements JSONTraverseAction +{ + @Override + public boolean start(JSONObject object) + { + return true; + } + + @Override + public boolean traverseEntry(String fullPathToEntry, Map.Entry entry) + { + System.out.println(entry.getKey()); + return true; + } + + @Override + public boolean recurInto(String pathToEntry, Object entryValue) { + return true; + } + + @Override + public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { + return true; + } + + @Override + public void handleLeaf(String pathToEntry, Object entryValue) + { + + } + + @Override + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) + { + + } + + @Override + public boolean removeEntry(String fullPathToEntry, Map.Entry entry) + { + return false; + } + + @Override + public void end() + { + + } + + @Override + public Object result() + { + return null; + } + +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java similarity index 57% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java rename to json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java index 6d7a3709..c26400d2 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java @@ -1,8 +1,8 @@ package net.minidev.json.actions.traverse; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.PathDelimiter; -import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -20,61 +20,68 @@ * @author adoneitan@gmail.com * */ -public class LocatePathsAction implements TraverseAction +public class LocatePathsJsonAction implements JSONTraverseAction { protected List pathsFound; protected List pathsToFind; + protected PathDelimiter delim; /** * * @param pathsToFind A path to a field in the {@link JSONObject} should be specified in n-gram format where keys are chained: * k0[[[.k1].k2]...] */ - public LocatePathsAction(List pathsToFind) + public LocatePathsJsonAction(List pathsToFind, PathDelimiter delim) { this.pathsToFind = pathsToFind; + this.delim = delim; pathsFound = new LinkedList(); } @Override - public boolean handleStart(JSONObject object) + public boolean start(JSONObject object) { return object != null && pathsToFind != null && pathsToFind.size() > 0; } @Override - public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + public boolean traverseEntry(String fullPathToEntry, Map.Entry entry) { - if (pathsToFind.contains(pathToEntry)) - { - //reached end of path that is being searched - pathsFound.add(pathToEntry); + if (!delim.accept(entry.getKey())) { + return false; } - return false; + locatePath(fullPathToEntry); + return true; } @Override - public boolean handleDotChar() { - return false; + public boolean recurInto(String pathToEntry, Object entryValue) { + return true; } @Override - public boolean handleNext() { + public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { return true; } @Override - public boolean handleJSONObjectChild() { - return true; + public void handleLeaf(String pathToEntry, Object entryValue) { + } @Override - public boolean handleJSONArrayChild() { - return true; + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) { + } @Override - public void handleEnd() { + public boolean removeEntry(String fullPathToEntry, Map.Entry entry) + { + return false; + } + + @Override + public void end() { //nothing to do } @@ -82,4 +89,13 @@ public void handleEnd() { public Object result() { return pathsFound; } + + private void locatePath(String pathToEntry) + { + if (pathsToFind.contains(pathToEntry)) + { + //reached end of path that is being searched + pathsFound.add(pathToEntry); + } + } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java similarity index 55% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java rename to json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java index 948ffac1..20ad762a 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java @@ -2,9 +2,8 @@ import net.minidev.json.JSONObject; -import java.util.Iterator; -import java.util.List; import java.util.Map; +import java.util.Map.Entry; /** * Removes key:value elements from a {@link JSONObject}. @@ -19,64 +18,67 @@ * @author adoneitan@gmail.com * */ -public class RemoveElementsAction implements TraverseAction +public class RemoveElementsJsonAction implements JSONTraverseAction { protected JSONObject result; protected final Map elementsToRemove; protected final boolean allowDotChar; - public RemoveElementsAction(Map elementsToRemove, boolean allowDotChar) + public RemoveElementsJsonAction(Map elementsToRemove, boolean allowDotChar) { this.elementsToRemove = elementsToRemove; this.allowDotChar = allowDotChar; } - public RemoveElementsAction(Map elementsToRemove) + public RemoveElementsJsonAction(Map elementsToRemove) { this(elementsToRemove, false); } @Override - public boolean handleStart(JSONObject object) + public boolean start(JSONObject object) { result = object; return object != null && elementsToRemove != null && elementsToRemove.size() > 0; } @Override - public boolean handleDotChar() { - return allowDotChar; - } - - @Override - public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + public boolean removeEntry(String fullPathToEntry, Entry entry) { - if (elementsToRemove.entrySet().contains(entry)) - { - it.remove(); - } - return false; + return elementsToRemove.entrySet().contains(entry); } @Override - public boolean handleNext() + public boolean traverseEntry(String fullPathToEntry, Entry entry) { //must traverse the whole object return true; } @Override - public boolean handleJSONObjectChild() { + public boolean recurInto(String pathToEntry, Object entryValue) { return true; } @Override - public boolean handleJSONArrayChild() { + public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { return true; } @Override - public void handleEnd() { + public void handleLeaf(String pathToEntry, Object entryValue) + { + + } + + @Override + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) + { + + } + + @Override + public void end() { //nothing to do } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java similarity index 56% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsAction.java rename to json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java index 0b41d8e9..859bdd5e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java @@ -2,7 +2,6 @@ import net.minidev.json.JSONObject; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -19,59 +18,60 @@ * @author adoneitan@gmail.com * */ -public class RemovePathsAction implements TraverseAction +public class RemovePathsJsonAction implements JSONTraverseAction { protected JSONObject result; protected List pathsToRemove; - public RemovePathsAction(List pathsToRemove) + public RemovePathsJsonAction(List pathsToRemove) { this.pathsToRemove = pathsToRemove; } @Override - public boolean handleStart(JSONObject object) + public boolean start(JSONObject object) { result = object; return object != null && pathsToRemove != null && pathsToRemove.size() > 0; } @Override - public boolean handleDotChar() { - return true; - } - - @Override - public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) + public boolean removeEntry(String fullPathToEntry, Map.Entry entry) { - if (pathsToRemove.contains(pathToEntry)) - { - it.remove(); - //the entry has been removed from the traversal iterator, no point in traversing its children - return true; - } - return false; + return pathsToRemove.contains(fullPathToEntry); } @Override - public boolean handleNext() + public boolean traverseEntry(String fullPathToEntry, Map.Entry entry) { //must traverse the whole object return true; } @Override - public boolean handleJSONObjectChild() { + public boolean recurInto(String pathToEntry, Object entryValue) { return true; } @Override - public boolean handleJSONArrayChild() { + public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { return true; } @Override - public void handleEnd() { + public void handleLeaf(String pathToEntry, Object entryValue) + { + + } + + @Override + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) + { + + } + + @Override + public void end() { //nothing to do } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java similarity index 50% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsAction.java rename to json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java index 49a9361e..7671a891 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java @@ -1,11 +1,11 @@ package net.minidev.json.actions.traverse; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.PathDelimiter; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import java.util.Map; +import java.util.Map.Entry; /** * Retain branches or parts of branches matching a specified list of paths. @@ -23,18 +23,20 @@ * @author adoneitan@gmail.com * */ -public class RetainPathsAction implements TraverseAction +public class RetainPathsJsonAction implements JSONTraverseAction { + private final PathDelimiter delim; protected JSONObject result; protected List pathsToRetain; - public RetainPathsAction(List pathsToRetain) + public RetainPathsJsonAction(List pathsToRetain, PathDelimiter delim) { this.pathsToRetain = new ArrayList(pathsToRetain); + this.delim = delim; } @Override - public boolean handleStart(JSONObject object) + public boolean start(JSONObject object) { if (object == null) { @@ -51,48 +53,35 @@ public boolean handleStart(JSONObject object) } @Override - public boolean handleEntryAndIgnoreChildren(String pathToEntry, Iterator> it, Map.Entry entry) - { - /** - * if the full path to the entry is not contained in any of the paths to retain - remove it from the object - * this step does not remove entries whose full path is contained in a path to retain but are not equal to an - * entry to retain - */ - if (!foundStartsWith(pathToEntry) || entry.getKey().contains(".")) - { - it.remove(); - //the entry has been removed from the traversal iterator, no point in traversing its children - return true; - } - return false; + public boolean traverseEntry(String fullPathToEntry, Entry entry) { + return true; } @Override - public boolean handleDotChar() - { - //need to reach handleEntryAndIgnoreChildren() in order to remove the path containing the dot char + public boolean recurInto(String fullPathToSubtree, Object entryValue) { return true; } @Override - public boolean handleNext() - { - //must traverse the whole object + public boolean recurInto(String fullPathToArrayItem, int arrIndex, Object entryValue) { return true; } @Override - public boolean handleJSONObjectChild() { - return true; + public void handleLeaf(String pathToEntry, Object entryValue) { } @Override - public boolean handleJSONArrayChild(){ - return true; + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) { } @Override - public void handleEnd() + public boolean removeEntry(String fullPathToEntry, Entry entry) { + return discardPath(fullPathToEntry, entry); + } + + @Override + public void end() { // nothing to do } @@ -102,7 +91,22 @@ public Object result() { return result; } - protected boolean foundStartsWith(String path) + /** + * if the full path to the entry is not contained in any of the paths to retain - remove it from the object + * this step does not remove entries whose full path is contained in a path to retain but are not equal to an + * entry to retain + */ + protected boolean discardPath(String pathToEntry, Entry entry) + { + if (!foundAsPrefix(pathToEntry) || !delim.accept(entry.getKey())) + { + //skip traversal of subtree and remove from the traversal iterator + return true; + } + return false; + } + + protected boolean foundAsPrefix(String path) { for (String p : pathsToRetain) { if (p == path || (p != null && path != null && p.startsWith(path))) { diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java deleted file mode 100755 index 6184c6f4..00000000 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TraverseAction.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.minidev.json.actions.traverse; - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; - -import java.util.Iterator; -import java.util.Map; - -/** - * An interface for a processing action on the nodes of a {@link JSONObject} while traversing it. - *

- * See package-info for more details - * - * @author adoneitan@gmail.com - */ -public interface TraverseAction -{ - /** - * called before any traversal of the {@link JSONObject} starts - * @return true if traversal should start at all - */ - boolean handleStart(JSONObject object); - - /** - * @return false if encountering a key containing a '.' char on the path should abort the traversal of the path - */ - boolean handleDotChar(); - - /** - * called for each entry in given level of the {@link JSONObject} - * @return false if children of the specified entry should not be traversed - */ - boolean handleEntryAndIgnoreChildren(String fullPathToObject, Iterator> it, Map.Entry entry); - - /** - * called before the next entry in a given level of the {@link JSONObject} is processed - * @return true if siblings of the last entry should be processed - */ - boolean handleNext(); - - /** - * called if the child of the currently processed entry is a {@link JSONObject} - * @return true if a {@link JSONObject} child of the current entry should be processed - */ - boolean handleJSONObjectChild(); - - /** - * called if the child of the currently processed entry is a {@link JSONArray} - * @return true if a {@link JSONArray} child of the current entry should be processed - */ - boolean handleJSONArrayChild(); - - /** - * called after the traversal ends, and just before the traversal method exits - */ - void handleEnd(); - - /** - * holds the result of the traversal, as assigned by the action implementing this interface - */ - Object result(); -} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java new file mode 100755 index 00000000..7ac97d71 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java @@ -0,0 +1,74 @@ +package net.minidev.json.actions.traverse; + +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * An interface for a processing action on the nodes of a {@link M} tree + * while traversing it. The order in which the callbacks are listed + * below is the order in which they are called by the {@link TreeTraverser} + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public interface TreeTraverseAction, L extends List> +{ + /** + * called before any traversal of the {@link M} tree starts + * @return true if traversal should start at all + */ + boolean start(M object); + + /** + * called when a new entry is encountered and before any processing is performed on it + * @return true if the entry should be processed + */ + boolean traverseEntry(String fullPathToEntry, Entry entry); + + /** + * the last callback for each entry in an {@link M} map. if this method returns true + * the {@link TreeTraverser} removes the entry from the map. there is no further + * handling of the entry. + * @return true if the entry and its subtree should be removed from the {@link M} tree + */ + boolean removeEntry(String fullPathToEntry, Entry entry); + + /** + * called when a non-leaf entry is encountered inside an {@Link M} object + * @return true if the non-leaf entry should be recursively traversed + */ + boolean recurInto(String fullPathToSubtree, Object entryValue); + + /** + * called when a non-leaf item is encountered inside an {@Link L} object + * @return true if the non-leaf item should be recursively traversed + */ + boolean recurInto(String fullPathToContainingList, int listIndex, Object entryValue); + + /** + * called for each leaf of an {@link M} map is encountered + * @param entryValue - the item + */ + void handleLeaf(String fullPathToEntry, Object entryValue); + + /** + * called for each leaf of an {@link L} list is encountered + * @param listItem - the item + * @param listIndex - the ordered location of the item in the list + */ + void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem); + + /** + * called after the traversal ends, + * and just before the {@link #start(M)} method exits + */ + void end(); + + /** + * holds the result of the traversal, + * as assigned by the action implementing this interface + */ + Object result(); +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java new file mode 100755 index 00000000..4fbf84e1 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java @@ -0,0 +1,106 @@ +package net.minidev.json.actions.traverse; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Traverses every node of a tree made up of a combination of {@link Map}s and {@link List}s + *

+ * {@link TreeTraverser} accepts an action and provides callback hooks for it to act + * on the traversed nodes at each significant step. See {@link TreeTraverseAction}. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + * + */ +public class TreeTraverser, L extends List> +{ + private TreeTraverseAction action; + + public TreeTraverser(TreeTraverseAction action) + { + this.action = action; + } + + public void traverse(M map) + { + if (action.start(map)){ + depthFirst("", map); + } + action.end(); + } + + private void depthFirst(String fullPathToMap, M map) + { + if (map == null || map.entrySet() == null || !action.recurInto(fullPathToMap, map)) { + return; + } + Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) + { + Entry entry = it.next(); + String fullPathToEntry = buildPath(fullPathToMap, entry.getKey()); + + if (!action.traverseEntry(fullPathToEntry, entry)) { + continue; + } + else if (action.removeEntry(fullPathToEntry, entry)) + { + it.remove(); + continue; + } + + if (instanceOfMap(entry.getValue())) + { + depthFirst(fullPathToEntry, (M) entry.getValue()); + } + else if (instanceOfList(entry.getValue())) + { + depthFirst(fullPathToEntry, (L) entry.getValue()); + } + else if (!instanceOfMap(entry) && !instanceOfList(entry)) + { + action.handleLeaf(fullPathToEntry, entry); + } + } + } + + private void depthFirst(String fullPathToList, L list) + { + if (!action.recurInto(fullPathToList, list)) { + return; + } + int listIndex = 0; + for (Object listItem : list.toArray()) + { + if (instanceOfMap(listItem) && action.recurInto(fullPathToList, listIndex, listItem)) + { + depthFirst(fullPathToList, (M) listItem); + } + else if (instanceOfList(listItem) && action.recurInto(fullPathToList, listIndex, listItem)) + { + depthFirst(fullPathToList, (L) listItem); + } + else + { + action.handleLeaf(fullPathToList, listIndex, listItem); + } + listIndex++; + } + } + + private String buildPath(String fullPathToObject, String entryKey) { + return "".equals(fullPathToObject) ? entryKey : fullPathToObject + "." + entryKey; + } + + private boolean instanceOfList(Object obj) { + return obj instanceof List; + } + + private boolean instanceOfMap(Object obj) { + return obj instanceof Map; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java index dcb334a3..5fba45b8 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java @@ -3,12 +3,12 @@ * Traverse all the nodes in a {@link net.minidev.json.JSONObject} and process them *

* The traversal starts at the root and moves breadth-first down the branches. - * The {@link net.minidev.json.actions.traverse.JSONTraverser} accepts a - * {@link net.minidev.json.actions.traverse.TraverseAction} and provides callback hooks at each significant - * step which the {@link net.minidev.json.actions.traverse.TraverseAction} may use to process + * The {@link net.minidev.json.actions.traverse.TreeTraverser} accepts a + * {@link net.minidev.json.actions.traverse.JSONTraverseAction} and provides callback hooks at each significant + * step which the {@link net.minidev.json.actions.traverse.JSONTraverseAction} may use to process * the nodes. *

- * The {@link net.minidev.json.actions.traverse.JSONTraverser} assumes that paths in the tree which the + * The {@link net.minidev.json.actions.traverse.TreeTraverser} assumes that paths in the tree which the * {@link net.minidev.json.JSONObject} represents are specified in the n-gram format - a list of keys from the * root down separated by dots: *

diff --git a/json-smart/src/test/java/net/minidev/json/actions/traverse/KeysPrintActionTest.java b/json-smart/src/test/java/net/minidev/json/actions/traverse/KeysPrintActionTest.java new file mode 100644 index 00000000..29f580d8 --- /dev/null +++ b/json-smart/src/test/java/net/minidev/json/actions/traverse/KeysPrintActionTest.java @@ -0,0 +1,43 @@ +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.parser.ParseException; +import org.junit.Test; + +/** + * @author adoneitan@gmail.com + * @since 30 May 2016 + */ +public class KeysPrintActionTest +{ + @Test + public void test() throws ParseException + { + KeysPrintAction p = new KeysPrintAction(); + JSONTraverser t = new JSONTraverser(p); + JSONObject jo = (JSONObject) JSONValue.parseWithException( + "{" + + "\"k0\":{" + + "\"k01\":{" + + "\"k011\":\"v2\"" + + "}" + + "}," + + "\"k1\":{" + + "\"k11\":{" + + "\"k111\":\"v5\"" + + "}," + + "\"k12\":{" + + "\"k121\":\"v5\"" + + "}" + + "}," + + "\"k3\":{" + + "\"k31\":{" + + "\"k311\":\"v5\"" + + "}" + + "}" + + "}" + ); + t.traverse(jo); + } +} \ No newline at end of file diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java index 54031296..4fae7f60 100755 --- a/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java @@ -1,6 +1,8 @@ package net.minidev.json.test.actions; -import net.minidev.json.actions.navigate.JSONPath; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.JSONPath; +import net.minidev.json.actions.path.PathDelimiter; import org.junit.Test; import static org.junit.Assert.assertFalse; @@ -11,10 +13,12 @@ */ public class JSONPathTest { + private static final PathDelimiter delim = new DotDelimiter().withAcceptDelimiterInNodeName(true); + @Test public void testIterator() { - JSONPath jp = new JSONPath("a.b.c"); + JSONPath jp = new JSONPath("a.b.c", delim); assertTrue(jp.nextIndex() == 0); assertTrue(jp.prevIndex() == -1); assertTrue("".equals(jp.curr())); @@ -70,14 +74,14 @@ public void testIterator() @Test public void testSubPath() { - JSONPath jp = new JSONPath("a.b.c"); + JSONPath jp = new JSONPath("a.b.c", delim); assertTrue(jp.subPath(1,2).equals("b.c")); } @Test public void testClone() throws CloneNotSupportedException { - JSONPath jp1 = new JSONPath("a.b.c"); + JSONPath jp1 = new JSONPath("a.b.c", delim); JSONPath jp2 = jp1.clone(); assertTrue(jp1.equals(jp2)); diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java index 890bbfcc..29734110 100755 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java @@ -51,28 +51,28 @@ public static Collection params() {"{}", "", new String[]{} }, {"{}", "k1", new String[]{} }, {"{}", new String[]{}, new String[]{} }, - {"{}", new JSONArray(), new String[]{} }, - {"{}", new ArrayList(0), new String[]{} },//11 + {"{}", new JSONArray(), new String[]{} },//10 + {"{}", new ArrayList(0), new String[]{} }, //simple json, bad/empty keys {"{\"k0\":\"v0\"}", null, new String[]{} }, {"{\"k0\":\"v0\"}", "", new String[]{} }, {"{\"k0\":\"v0\"}", "k1", new String[]{} }, - {"{\"k0\":\"v0\"}", new String[]{}, new String[]{} }, + {"{\"k0\":\"v0\"}", new String[]{}, new String[]{} },//15 {"{\"k0\":\"v0\"}", new JSONArray(), new String[]{} }, - {"{\"k0\":\"v0\"}", new ArrayList(0), new String[]{} },//17 + {"{\"k0\":\"v0\"}", new ArrayList(0), new String[]{} }, //simple json, valid/invalid keys {"{\"k0\":\"v0\"}", "k0", new String[]{"k0"} }, {"{\"k0\":\"v0\"}", "v0", new String[]{} }, - {"{\"k0\":\"v0\"}", "k0.k1", new String[]{} }, + {"{\"k0\":\"v0\"}", "k0.k1", new String[]{} },//20 {"{\"k0\":\"v0\"}", "k1.k0", new String[]{} }, {"{\"k0\":null}", "k0", new String[]{"k0"} }, - {"{\"k0\":null}", null, new String[]{} },//23 + {"{\"k0\":null}", null, new String[]{} }, //key with dot char {"{\"k0.k1\":\"v0\"}", "k0", new String[]{} }, - {"{\"k0.k1\":\"v0\"}", "k1", new String[]{} }, + {"{\"k0.k1\":\"v0\"}", "k1", new String[]{} },//25 {"{\"k0.k1\":\"v0\"}", "k0.k1", new String[]{} }, // key with dot ambiguity @@ -86,19 +86,19 @@ public static Collection params() {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k1.k2", new String[]{"k1.k2"} }, //ignore non-existent keys but keep good keys - {"{\"k0\":\"v0\",\"k1\":\"v1\"}", new String[]{"k0","k2"}, new String[]{"k0"} }, + {"{\"k0\":\"v0\",\"k1\":\"v1\"}", new String[]{"k0","k2"}, new String[]{"k0"} },//35 {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k2"}, new String[]{"k0"} }, {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2"}, new String[]{"k0", "k1.k2"} }, {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2.k3"}, new String[]{"k0"} }, {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2","k1"}, new String[]{"k0","k1","k1.k2"} }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k0.k2"}, new String[]{"k0","k1"} }, + {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k0.k2"}, new String[]{"k0","k1"} },//40 {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k2"}, new String[]{"k0","k1"} }, {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2"}, new String[]{"k1.k2"} }, //arrays - key inside array treated as child {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0", new String[]{"k0"} }, {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", new String[]{"k0.k1"} }, - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", new String[]{"k0.k1.k2"} }, + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", new String[]{"k0.k1.k2"} },//45 {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1.k2", new String[]{"k0.k1.k2", "k0.k1.k2"} }, }); } @@ -107,8 +107,8 @@ public static Collection params() public void test() throws ParseException { JSONObject objectToSearch = jsonToSearch != null ? (JSONObject) JSONValue.parseWithException(jsonToSearch) : null; - PathLocator f = switchKeyToRemove(); - List found = f.find(objectToSearch); + PathLocator locator = switchKeyToRemove(); + List found = locator.locate(objectToSearch); assertEquals(Arrays.asList(expectedFound), found); } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java index 51d9c813..2f18cfc7 100755 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java @@ -49,11 +49,11 @@ public static Collection params() {"{\"first\": null}", new ArrayList(0), "{\"first\": null}" }, // empty list key {"{\"first\": null}", "first", "{}" }, // remove root key {"{\"first.f1\": null}", "first.f1", "{}" }, // key with dot - {"{\"first.f1\": \"withDot\", \"first\":{\"f1\": null}}", "first.f1", "{\"first\":{}}" }, // key with dot ambiguity + {"{\"first.f1\": \"withDot\", \"first\":{\"f1\": null}}", "first.f1", "{\"first\":{}}" }, //9 key with dot ambiguity {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{}}}}" }, // nested object remove single leaf {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "notfound", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, // nested object key does not exist {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{\"name\":\"me\"}}}}"}, // nested object remove first leaf - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.name", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, // nested object remove last leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.name", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, //13 nested object remove last leaf {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3", "{\"first\":{\"f2\":{}}}" }, // nested object remove intermediate node {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first", "{}" }, // nested object remove root {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2.id", "{\"first\":{\"f2\":[[1,{},3],4]}}" }, // double nested array remove leaf diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java index c6cee591..17daf438 100755 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java @@ -4,6 +4,7 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.JSONValue; +import net.minidev.json.actions.path.DotDelimiter; import net.minidev.json.parser.ParseException; import org.junit.Test; import org.junit.runner.RunWith; @@ -78,9 +79,9 @@ public static Collection params() // key with dot ambiguity {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0", "{\"k0\":{}}" },//27 {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k1", "{}" }, - {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0.k1", "{\"k0\":{\"k1\":null}}" }, + {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0.k1", "{\"k0\":{\"k1\":null}}" },//29 {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1", "{\"k0\":{\"k1\":{}}}" }, - {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1.k2", "{\"k0\":{\"k1\":{\"k2\":null}}}" }, + {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1.k2", "{\"k0\":{\"k1\":{\"k2\":null}}}" },//31 {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k1.k2", "{}" }, {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k0", "{\"k0\":{}}}" }, {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k1.k2", "{\"k1\":{\"k2\":\"v2\"}}}" }, @@ -116,8 +117,8 @@ public void test() throws ParseException { JSONObject objectToReduce = jsonToReduce != null ? (JSONObject) JSONValue.parseWithException(jsonToReduce) :null; JSONObject expectedReducedObj = expectedReducedJson != null ? (JSONObject) JSONValue.parseWithException(expectedReducedJson):null; - PathsRetainer reducer = switchKeyToRemove(); - JSONObject reducedObj = reducer.retain(objectToReduce); + PathsRetainer retainer = switchKeyToRemove().with(new DotDelimiter().withAcceptDelimiterInNodeName(false)); + JSONObject reducedObj = retainer.retain(objectToReduce); assertEquals(expectedReducedObj, reducedObj); } From 4de36a492589797d85815651416348d762fc4390 Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Tue, 7 Jun 2016 16:23:31 +0300 Subject: [PATCH 06/18] support any delimiter in traverser --- json-smart/pom.xml | 8 ++++++- .../net/minidev/json/actions/PathLocator.java | 2 +- .../minidev/json/actions/PathsRetainer.java | 2 +- .../json/actions/path/PathDelimiter.java | 2 +- .../json/actions/path/SlashDelimiter.java | 24 +++++++++++++++++++ .../json/actions/traverse/JSONTraverser.java | 9 ++++++- .../json/actions/traverse/TreeTraverser.java | 10 +++++--- 7 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java diff --git a/json-smart/pom.xml b/json-smart/pom.xml index 6f8ef200..5e35f2f1 100644 --- a/json-smart/pom.xml +++ b/json-smart/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.minidev json-smart - 2.2.1 + 2.2.1-b-SNAPSHOT JSON Small and Fast Parser JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. @@ -23,6 +23,12 @@ + + erav + Eitan Raviv + adoneitan@gmail.com + GMT+2 + diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java index e66eea55..773807a7 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java @@ -67,7 +67,7 @@ public PathLocator with(PathDelimiter pathDelimiter) { public List locate(JSONObject object) { JSONTraverseAction action = new LocatePathsJsonAction(this.pathsToFind, pathDelimiter); - JSONTraverser traversal = new JSONTraverser(action); + JSONTraverser traversal = new JSONTraverser(action).with(pathDelimiter); traversal.traverse(object); return (List) action.result(); } diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java index 7e256814..f0d32783 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java @@ -86,7 +86,7 @@ public JSONObject retain(JSONObject object) //now reduce the object using only existing paths JSONTraverseAction retainer = new RetainPathsJsonAction(realPathsToRetain, pathDelimiter); - JSONTraverser t2 = new JSONTraverser(retainer); + JSONTraverser t2 = new JSONTraverser(retainer).with(pathDelimiter); t2.traverse(object); return (JSONObject) retainer.result(); } diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java index 494406cb..2a9fae7d 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java @@ -4,7 +4,7 @@ * Encapsulates the delimiter of the path parts when given in n-gram format. * * @author adoneitan@gmail.com - * @since 31 May2016 + * @since 31 May 2016 */ public abstract class PathDelimiter { diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java new file mode 100644 index 00000000..1c005f2f --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java @@ -0,0 +1,24 @@ +package net.minidev.json.actions.path; + +/** + * Encapsulates the delimiter '.' of the path parts when the path is specified in n-gram format. + * For example: root.node1.node11.leaf + * + * @author adoneitan@gmail.com + * @since 31 May 2016 + */ +public class SlashDelimiter extends PathDelimiter +{ + protected static final char DELIM_CHAR = '/'; + + public SlashDelimiter() + { + super(DELIM_CHAR); + super.withAcceptDelimiterInNodeName(false); + } + + public String regex() + { + return "\\/"; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java index 2a6d62a0..62dd307e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java @@ -2,6 +2,8 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.PathDelimiter; /** * Traverses every node of a {@link JSONObject} @@ -23,6 +25,11 @@ public class JSONTraverser extends TreeTraverser public JSONTraverser(JSONTraverseAction action) { - super(action); + super(action, new DotDelimiter()); + } + + public JSONTraverser with(PathDelimiter delim) { + super.delim = delim; + return this; } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java index 4fbf84e1..6292d489 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java @@ -1,5 +1,7 @@ package net.minidev.json.actions.traverse; +import net.minidev.json.actions.path.PathDelimiter; + import java.util.Iterator; import java.util.List; import java.util.Map; @@ -18,11 +20,13 @@ */ public class TreeTraverser, L extends List> { - private TreeTraverseAction action; + protected PathDelimiter delim; + protected TreeTraverseAction action; - public TreeTraverser(TreeTraverseAction action) + public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) { this.action = action; + this.delim = delim; } public void traverse(M map) @@ -93,7 +97,7 @@ else if (instanceOfList(listItem) && action.recurInto(fullPathToList, listIndex, } private String buildPath(String fullPathToObject, String entryKey) { - return "".equals(fullPathToObject) ? entryKey : fullPathToObject + "." + entryKey; + return "".equals(fullPathToObject) ? entryKey : fullPathToObject + delim.str() + entryKey; } private boolean instanceOfList(Object obj) { From efb8714ede7a7389144ed0ed85336201d76d6dfb Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Wed, 8 Jun 2016 15:46:00 +0300 Subject: [PATCH 07/18] simplif api --- .../net/minidev/json/actions/PathLocator.java | 4 ++-- .../net/minidev/json/actions/PathRemover.java | 2 +- .../net/minidev/json/actions/PathsRetainer.java | 2 +- .../json/actions/navigate/CopyPathsAction.java | 6 +++--- .../json/actions/traverse/JSONTraverser.java | 2 -- .../json/actions/traverse/KeysPrintAction.java | 15 +++++++-------- .../actions/traverse/LocatePathsJSONAction.java | 13 +++++++------ .../traverse/RemoveElementsJSONAction.java | 7 ++++--- .../actions/traverse/RemovePathsJsonAction.java | 13 +++++++------ .../actions/traverse/RetainPathsJsonAction.java | 9 +++++---- .../json/actions/traverse/TreeTraverseAction.java | 7 +++---- .../json/actions/traverse/TreeTraverser.java | 8 ++++---- 12 files changed, 44 insertions(+), 44 deletions(-) diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java index 773807a7..e75d5736 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java @@ -30,8 +30,8 @@ */ public class PathLocator { - private List pathsToFind; - private PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); + protected List pathsToFind; + protected PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); public PathLocator(JSONArray pathsToFind) { diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java index f2532da4..c8c4db37 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java @@ -36,7 +36,7 @@ */ public class PathRemover { - private List pathsToRemove; + protected List pathsToRemove; public PathRemover(JSONArray pathsToRemove) { diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java index f0d32783..f4fa2496 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java @@ -36,7 +36,7 @@ public class PathsRetainer { protected List pathsToRetain; - private PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); + protected PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); public PathsRetainer(JSONArray pathsToRetain) { diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java index ba62fafd..20cb4a02 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -29,9 +29,9 @@ */ public class CopyPathsAction implements NavigateAction { - private JSONObject destTree; - private JSONObject destBranch; - private Stack destNodeStack; + protected JSONObject destTree; + protected JSONObject destBranch; + protected Stack destNodeStack; @Override public boolean handleNavigationStart(JSONObject source, Collection pathsToCopy) diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java index 62dd307e..eb55c092 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java @@ -21,8 +21,6 @@ */ public class JSONTraverser extends TreeTraverser { - private JSONTraverseAction action; - public JSONTraverser(JSONTraverseAction action) { super(action, new DotDelimiter()); diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java index b3e8e993..55b4c47a 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java @@ -1,10 +1,9 @@ package net.minidev.json.actions.traverse; +import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; -import net.minidev.json.JSONValue; -import net.minidev.json.parser.ParseException; -import java.util.Map; +import java.util.Map.Entry; /** * @author adoneitan@gmail.com @@ -19,24 +18,24 @@ public boolean start(JSONObject object) } @Override - public boolean traverseEntry(String fullPathToEntry, Map.Entry entry) + public boolean traverseEntry(String fullPathToEntry, Entry entry) { System.out.println(entry.getKey()); return true; } @Override - public boolean recurInto(String pathToEntry, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONObject entryValue) { return true; } @Override - public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONArray entryValue) { return true; } @Override - public void handleLeaf(String pathToEntry, Object entryValue) + public void handleLeaf(String pathToEntry, Entry entry) { } @@ -48,7 +47,7 @@ public void handleLeaf(String fullPathToContainingList, int listIndex, Object li } @Override - public boolean removeEntry(String fullPathToEntry, Map.Entry entry) + public boolean removeEntry(String fullPathToEntry, Entry entry) { return false; } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java index c26400d2..f798c03e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java @@ -1,11 +1,12 @@ package net.minidev.json.actions.traverse; +import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.actions.path.PathDelimiter; import java.util.LinkedList; import java.util.List; -import java.util.Map; +import java.util.Map.Entry; /** * Searches for paths in a {@link JSONObject} and returns those found @@ -45,7 +46,7 @@ public boolean start(JSONObject object) } @Override - public boolean traverseEntry(String fullPathToEntry, Map.Entry entry) + public boolean traverseEntry(String fullPathToEntry, Entry entry) { if (!delim.accept(entry.getKey())) { return false; @@ -55,17 +56,17 @@ public boolean traverseEntry(String fullPathToEntry, Map.Entry e } @Override - public boolean recurInto(String pathToEntry, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONObject entryValue) { return true; } @Override - public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONArray entryValue) { return true; } @Override - public void handleLeaf(String pathToEntry, Object entryValue) { + public void handleLeaf(String pathToEntry, Entry entry) { } @@ -75,7 +76,7 @@ public void handleLeaf(String fullPathToContainingList, int listIndex, Object li } @Override - public boolean removeEntry(String fullPathToEntry, Map.Entry entry) + public boolean removeEntry(String fullPathToEntry, Entry entry) { return false; } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java index 20ad762a..f8a4d7d4 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java @@ -1,5 +1,6 @@ package net.minidev.json.actions.traverse; +import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import java.util.Map; @@ -56,17 +57,17 @@ public boolean traverseEntry(String fullPathToEntry, Entry entry } @Override - public boolean recurInto(String pathToEntry, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONObject entryValue) { return true; } @Override - public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONArray entryValue) { return true; } @Override - public void handleLeaf(String pathToEntry, Object entryValue) + public void handleLeaf(String pathToEntry, Entry entry) { } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java index 859bdd5e..fac23fd5 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java @@ -1,9 +1,10 @@ package net.minidev.json.actions.traverse; +import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import java.util.List; -import java.util.Map; +import java.util.Map.Entry; /** * Removes branches from a {@link JSONObject}. @@ -36,30 +37,30 @@ public boolean start(JSONObject object) } @Override - public boolean removeEntry(String fullPathToEntry, Map.Entry entry) + public boolean removeEntry(String fullPathToEntry, Entry entry) { return pathsToRemove.contains(fullPathToEntry); } @Override - public boolean traverseEntry(String fullPathToEntry, Map.Entry entry) + public boolean traverseEntry(String fullPathToEntry, Entry entry) { //must traverse the whole object return true; } @Override - public boolean recurInto(String pathToEntry, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONObject entryValue) { return true; } @Override - public boolean recurInto(String pathToEntry, int listIndex, Object entryValue) { + public boolean recurInto(String pathToEntry, JSONArray entryValue) { return true; } @Override - public void handleLeaf(String pathToEntry, Object entryValue) + public void handleLeaf(String pathToEntry, Entry entry) { } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java index 7671a891..1948da93 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java @@ -1,5 +1,6 @@ package net.minidev.json.actions.traverse; +import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.actions.path.PathDelimiter; @@ -25,7 +26,7 @@ */ public class RetainPathsJsonAction implements JSONTraverseAction { - private final PathDelimiter delim; + protected final PathDelimiter delim; protected JSONObject result; protected List pathsToRetain; @@ -58,17 +59,17 @@ public boolean traverseEntry(String fullPathToEntry, Entry entry } @Override - public boolean recurInto(String fullPathToSubtree, Object entryValue) { + public boolean recurInto(String fullPathToSubtree, JSONObject entryValue) { return true; } @Override - public boolean recurInto(String fullPathToArrayItem, int arrIndex, Object entryValue) { + public boolean recurInto(String fullPathToArrayItem, JSONArray entryValue) { return true; } @Override - public void handleLeaf(String pathToEntry, Object entryValue) { + public void handleLeaf(String pathToEntry, Entry entry) { } @Override diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java index 7ac97d71..61922c8d 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java @@ -39,19 +39,18 @@ public interface TreeTraverseAction, L extends Lis * called when a non-leaf entry is encountered inside an {@Link M} object * @return true if the non-leaf entry should be recursively traversed */ - boolean recurInto(String fullPathToSubtree, Object entryValue); + boolean recurInto(String fullPathToSubtree, M entryValue); /** * called when a non-leaf item is encountered inside an {@Link L} object * @return true if the non-leaf item should be recursively traversed */ - boolean recurInto(String fullPathToContainingList, int listIndex, Object entryValue); + boolean recurInto(String fullPathToContainingList, L entryValue); /** * called for each leaf of an {@link M} map is encountered - * @param entryValue - the item */ - void handleLeaf(String fullPathToEntry, Object entryValue); + void handleLeaf(String fullPathToEntry, Entry entry); /** * called for each leaf of an {@link L} list is encountered diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java index 6292d489..89b78fe5 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java @@ -65,7 +65,7 @@ else if (instanceOfList(entry.getValue())) { depthFirst(fullPathToEntry, (L) entry.getValue()); } - else if (!instanceOfMap(entry) && !instanceOfList(entry)) + else { action.handleLeaf(fullPathToEntry, entry); } @@ -74,17 +74,17 @@ else if (!instanceOfMap(entry) && !instanceOfList(entry)) private void depthFirst(String fullPathToList, L list) { - if (!action.recurInto(fullPathToList, list)) { + if (!action.recurInto(fullPathToList, (L) list)) { return; } int listIndex = 0; for (Object listItem : list.toArray()) { - if (instanceOfMap(listItem) && action.recurInto(fullPathToList, listIndex, listItem)) + if (instanceOfMap(listItem)) { depthFirst(fullPathToList, (M) listItem); } - else if (instanceOfList(listItem) && action.recurInto(fullPathToList, listIndex, listItem)) + else if (instanceOfList(listItem)) { depthFirst(fullPathToList, (L) listItem); } From 5391effad93d79854fd580bc3f48603cbfb2df0c Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Sun, 19 Jun 2016 20:52:14 +0300 Subject: [PATCH 08/18] create tree navigator --- .../net/minidev/json/actions/JSONBuilder.java | 17 ++ .../actions/navigate/CopyPathsAction.java | 35 ++-- .../actions/navigate/JSONNavigateAction.java | 16 ++ .../navigate/JSONNavigateActionOld.java | 103 ++++++++++ .../json/actions/navigate/JSONNavigator.java | 180 +---------------- .../actions/navigate/JSONNavigatorOld.java | 191 ++++++++++++++++++ .../json/actions/navigate/NavigateAction.java | 62 +++--- .../json/actions/navigate/TreeNavigator.java | 171 ++++++++++++++++ .../json/actions/navigate/package-info.java | 4 +- .../path/{JSONPath.java => TreePath.java} | 34 ++-- .../json/actions/traverse/TreeTraverser.java | 45 ++--- .../{JSONPathTest.java => TreePathTest.java} | 16 +- 12 files changed, 603 insertions(+), 271 deletions(-) create mode 100644 json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java create mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java rename json-smart/src/main/java/net/minidev/json/actions/path/{JSONPath.java => TreePath.java} (87%) rename json-smart/src/test/java/net/minidev/json/test/actions/{JSONPathTest.java => TreePathTest.java} (87%) diff --git a/json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java b/json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java new file mode 100644 index 00000000..23e65245 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java @@ -0,0 +1,17 @@ +package net.minidev.json.actions; + +import net.minidev.json.JSONObject; + +/** + * @author adoneitan@gmail.com + * @since 14 June 2016 + */ +public class JSONBuilder +{ + protected JSONObject result; + + public void append(String path, String value) + { + + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java index 20cb4a02..42d0797c 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -2,7 +2,7 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.JSONPath; +import net.minidev.json.actions.path.TreePath; import java.util.Collection; import java.util.Stack; @@ -27,14 +27,14 @@ * @author adoneitan@gmail.com * */ -public class CopyPathsAction implements NavigateAction +public class CopyPathsAction implements JSONNavigateAction { protected JSONObject destTree; protected JSONObject destBranch; protected Stack destNodeStack; @Override - public boolean handleNavigationStart(JSONObject source, Collection pathsToCopy) + public boolean start(JSONObject source, Collection pathsToCopy) { if (source == null) { @@ -55,15 +55,18 @@ public boolean handleNavigationStart(JSONObject source, Collection paths } @Override - public boolean handleJSONObject(JSONPath jp, JSONObject o) + public boolean recurInto(TreePath jp, JSONObject o) { //reached JSONObject node - instantiate it and recur handleNewNode(jp, new JSONObject()); return true; } - private void handleNewNode(JSONPath jp, Object node) + private void handleNewNode(TreePath jp, Object node) { + if (!jp.hasPrev()) { + return; + } if (destNodeStack.peek() instanceof JSONObject) { ((JSONObject) destNodeStack.peek()).put(jp.curr(), node); } @@ -74,7 +77,7 @@ else if (destNodeStack.peek() instanceof JSONArray) { } @Override - public boolean handleJSONArrray(JSONPath jp, JSONArray o) + public boolean recurInto(TreePath jp, JSONArray o) { //reached JSONArray node - instantiate it and recur handleNewNode(jp, new JSONArray()); @@ -82,32 +85,32 @@ public boolean handleJSONArrray(JSONPath jp, JSONArray o) } @Override - public void handlePrematureNavigatedBranchEnd(JSONPath jp, Object source) { + public void handlePrematureNavigatedBranchEnd(TreePath jp, Object source) { throw new IllegalArgumentException("branch is shorter than path - path not found in source: '" + jp.origin() + "'"); } @Override - public void handleJSONObjectLeaf(JSONPath jp, Object o) { + public void handleLeaf(TreePath jp, Object o) { ((JSONObject) destNodeStack.peek()).put(jp.curr(), o); } @Override - public void handleJSONArrayLeaf(int arrIndex, Object o) { + public void handleLeaf(TreePath jp, int arrIndex, Object o) { ((JSONArray) destNodeStack.peek()).add(o); } @Override - public void handleJSONArrayEnd(JSONPath jp) { + public void recurEnd(TreePath jp, JSONObject jo) { destNodeStack.pop(); } @Override - public void handleObjectEnd(JSONPath jp) { + public void recurEnd(TreePath jp, JSONArray ja) { destNodeStack.pop(); } @Override - public boolean handleNextPath(String path) + public boolean pathStart(String path) { destBranch = new JSONObject(); destNodeStack = new Stack(); @@ -116,22 +119,22 @@ public boolean handleNextPath(String path) } @Override - public void handlePathEnd(String path) { + public void pathEnd(String path) { destTree.merge(destBranch); } @Override - public boolean failPathSilently(String path, Exception e) { + public boolean failSilently(String path, Exception e) { return false; } @Override - public boolean failPathFast(String path, Exception e) { + public boolean failFast(String path, Exception e) { return false; } @Override - public void handleNavigationEnd() { + public void end() { } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java new file mode 100755 index 00000000..eff79f8d --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java @@ -0,0 +1,16 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; + +/** + * An interface for a processing action on the nodes of a {@link JSONObject} while navigating its branches. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public interface JSONNavigateAction extends NavigateAction +{ + +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java new file mode 100755 index 00000000..c46aa5fe --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java @@ -0,0 +1,103 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.TreePath; + +import java.util.Collection; + +/** + * An interface for a processing action on the nodes of a {@link JSONObject} while navigating its branches. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + */ +public interface JSONNavigateActionOld +{ + /** + * called before any navigation of the {@link JSONObject} starts + * @return true if navigation should start at all + */ + boolean handleNavigationStart(JSONObject objectToNavigate, Collection pathsToNavigate); + + /** + * called before navigation of a new path starts + * @return true if the specified path should be navigated + */ + boolean handleNextPath(String path); + + /** + * reached end of branch in source before end of specified json path - + * the specified path does not exist in the source. + */ + void handlePrematureNavigatedBranchEnd(TreePath jp, Object source); + + /** + * called after the navigation of a path ends + */ + void handlePathEnd(String path); + + /** + * called if navigation of a path throws an exception + * @return true if the failure on this path should not abort the rest of the navigation + */ + boolean failPathSilently(String path, Exception e); + + /** + * called if navigation of a path throws an exception + * @return true if the failure on this path should abort the rest of the navigation + */ + boolean failPathFast(String path, Exception e); + + /** + * called when an object node is encountered on the path + * @return true if the navigator should navigate into the object + */ + boolean handleJSONObject(TreePath jp, JSONObject sourceNode); + + /** + * called when an array node is encountered on the path + * @return true if the navigator should navigate into the array + */ + boolean handleJSONArrray(TreePath jp, JSONArray sourceNode); + + /** + * called when a leaf node is reached in a JSONObject. + * a leaf in a JSONObject is a key-value pair where the value is not a container itself + * (it is not a JSONObject nor a JSONArray) + * @param jp - the JsonPath pointing to the leaf + */ + void handleJSONObjectLeaf(TreePath jp, Object value); + + /** + * called when a leaf in a JSONArray is reached. + * a leaf in a JSONArray is a non-container item + * (it is not a JSONObject nor a JSONArray) + * @param arrIndex - the index of the item in the JSONArray + * @param arrItem - the item + */ + void handleJSONArrayLeaf(int arrIndex, Object arrItem); + + /** + * called after all the items of an array have been visited + * @param jp - the JsonPath pointing to the array + */ + void handleJSONArrayEnd(TreePath jp); + + /** + * called after all the entries of a JSONObject have been visited + * @param jp - the JsonPath pointing to the object + */ + void handleObjectEnd(TreePath jp); + + /** + * called after all navigation ends, and just before the navigation method exits + */ + void handleNavigationEnd(); + + /** + * holds the result of the navigation, as assigned by the action implementing this interface + */ + Object result(); +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java old mode 100755 new mode 100644 index 06da109f..4030be92 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java @@ -2,190 +2,22 @@ import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.DotDelimiter; -import net.minidev.json.actions.path.JSONPath; -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; import java.util.List; /** - * Navigates only the branches of a {@link JSONObject} corresponding to the paths specified. - *

- * For each specified path to navigate, the {@link JSONNavigator} only traverses the matching - * branch. - *

- * The navigator accepts an action and provides callback hooks for it to act on the traversed - * nodes at each significant step. See {@link NavigateAction}. - *

- * See package-info for more details - *

- * Example: - *

- * To navigate the branch k1.k2 of the object {"k1":{"k2":"v1"}, "k3":{"k4":"v2"}} instantiate - * the navigator like so: new JSONNavigator("k1.k2") - * - * @author adoneitan@gmail.com - * + * Created by eitanraviv on 6/15/16. */ -public class JSONNavigator +public class JSONNavigator extends TreeNavigator { - protected List pathsToNavigate; - protected NavigateAction action; - public JSONNavigator(NavigateAction action, JSONArray pathsToNavigate) + public JSONNavigator(JSONNavigateAction action, List pathsToNavigate) { - if (action == null) { - throw new IllegalArgumentException("NavigateAction cannot be null"); - } - this.action = action; - if (pathsToNavigate == null || pathsToNavigate.isEmpty()) { - this.pathsToNavigate = Collections.emptyList(); - } - else - { - this.pathsToNavigate = new LinkedList(); - for (Object s : pathsToNavigate) { - this.pathsToNavigate.add((String) s); - } - } + super(action, pathsToNavigate); } - public JSONNavigator(NavigateAction action, List pathsToNavigate) + public JSONNavigator(JSONNavigateAction action, String... pathsToNavigate) { - if (action == null) { - throw new IllegalArgumentException("NavigateAction cannot be null"); - } - this.action = action; - this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.size() == 0 ? - Collections.emptyList() : pathsToNavigate; - } - - public JSONNavigator(NavigateAction action, String... pathsToNavigate) - { - if (action == null) { - throw new IllegalArgumentException("NavigateAction cannot be null"); - } - this.action = action; - this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.length == 0 ? - Collections.emptyList() : new LinkedList(Arrays.asList(pathsToNavigate)); - } - - public void nav(JSONObject object) throws Exception - { - if (action.handleNavigationStart(object, pathsToNavigate)) - { - for (String path: pathsToNavigate) - { - try - { - if (path != null && !path.equals("") && action.handleNextPath(path)) - { - JSONPath jp = new JSONPath(path, new DotDelimiter().withAcceptDelimiterInNodeName(true)); - nav(object, jp); - action.handlePathEnd(path); - } - } - catch (Exception e) - { - if (action.failPathSilently(path ,e)) { - break; - } - else if (action.failPathFast(path, e)) { - throw e; - } - } - } - } - action.handleNavigationEnd(); - } - - private void nav(JSONObject source, JSONPath jp) - { - if (jp.hasNext()) - { - if (source == null) - { - //source is null - navigation impossible - return; - } - String next = jp.next(); - if (!source.containsKey(next)) - { - // reached end of branch in source before end of specified json path - - // the specified path is illegal because it does not exist in the source. - action.handlePrematureNavigatedBranchEnd(jp, source); - } - else if (source.get(next) instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) source.get(next))) - { - //reached JSONObject node - handle it and recur into it - nav((JSONObject) source.get(next), jp); - } - else if (source.get(next) instanceof JSONArray && action.handleJSONArrray(jp, (JSONArray) source.get(next))) - { - //reached JSONArray node - handle it and recur into it - nav((JSONArray) source.get(next), jp); - } - else if (jp.hasNext()) - { - // reached leaf node (not a container) in source but specified path expects children - - // the specified path is illegal because it does not exist in the source. - action.handlePrematureNavigatedBranchEnd(jp, source.get(next)); - } - else if (!jp.hasNext()) - { - //reached leaf in source and specified path is also at leaf -> handle it - action.handleJSONObjectLeaf(jp, source.get(next)); - } - else - { - throw new IllegalStateException("fatal: unreachable code reached at '" + jp.origin() + "'"); - } - } - action.handleObjectEnd(jp); - } - - private void nav(JSONArray source, JSONPath jp) - { - if (source == null) - { - //array is null - navigation impossible - return; - } - int arrIndex = 0; - for (Object arrItem : source.toArray()) - { - if (arrItem instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) arrItem)) - { - // clone the path so that for each JSONObject in the array, - // the iterator continues from the same position in the path - JSONPath jpClone = getClone(jp); - nav((JSONObject) arrItem, jpClone); - } - else if (arrItem instanceof JSONArray) - { - throw new IllegalArgumentException("illegal json - found array nested inside array at: '" + jp.origin() + "'"); - } - else if (!jp.hasNext()) - { - //reached leaf - handle it - action.handleJSONArrayLeaf(arrIndex, arrItem); - } - arrIndex++; - } - action.handleJSONArrayEnd(jp); - - } - - private JSONPath getClone(JSONPath jp) - { - try - { - return jp.clone(); - } - catch (CloneNotSupportedException e) { - throw new RuntimeException("failed to clone json path", e); - } + super(action, pathsToNavigate); } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java new file mode 100755 index 00000000..2b4467f9 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java @@ -0,0 +1,191 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.TreePath; + +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * Navigates only the branches of a {@link JSONObject} corresponding to the paths specified. + *

+ * For each specified path to navigate, the {@link JSONNavigatorOld} only traverses the matching + * branch. + *

+ * The navigator accepts an action and provides callback hooks for it to act on the traversed + * nodes at each significant step. See {@link JSONNavigateActionOld}. + *

+ * See package-info for more details + *

+ * Example: + *

+ * To navigate the branch k1.k2 of the object {"k1":{"k2":"v1"}, "k3":{"k4":"v2"}} instantiate + * the navigator like so: new JSONNavigator("k1.k2") + * + * @author adoneitan@gmail.com + * + */ +public class JSONNavigatorOld +{ + protected List pathsToNavigate; + protected JSONNavigateActionOld action; + + public JSONNavigatorOld(JSONNavigateActionOld action, JSONArray pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("JSONNavigateActionOld cannot be null"); + } + this.action = action; + if (pathsToNavigate == null || pathsToNavigate.isEmpty()) { + this.pathsToNavigate = Collections.emptyList(); + } + else + { + this.pathsToNavigate = new LinkedList(); + for (Object s : pathsToNavigate) { + this.pathsToNavigate.add((String) s); + } + } + } + + public JSONNavigatorOld(JSONNavigateActionOld action, List pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("JSONNavigateActionOld cannot be null"); + } + this.action = action; + this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.size() == 0 ? + Collections.emptyList() : pathsToNavigate; + } + + public JSONNavigatorOld(JSONNavigateActionOld action, String... pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("JSONNavigateActionOld cannot be null"); + } + this.action = action; + this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.length == 0 ? + Collections.emptyList() : new LinkedList(Arrays.asList(pathsToNavigate)); + } + + public void nav(JSONObject object) throws Exception + { + if (action.handleNavigationStart(object, pathsToNavigate)) + { + for (String path: pathsToNavigate) + { + try + { + if (path != null && !path.equals("") && action.handleNextPath(path)) + { + TreePath jp = new TreePath(path, new DotDelimiter().withAcceptDelimiterInNodeName(true)); + nav(object, jp); + action.handlePathEnd(path); + } + } + catch (Exception e) + { + if (action.failPathSilently(path ,e)) { + break; + } + else if (action.failPathFast(path, e)) { + throw e; + } + } + } + } + action.handleNavigationEnd(); + } + + private void nav(JSONObject source, TreePath jp) + { + if (jp.hasNext()) + { + if (source == null) + { + //source is null - navigation impossible + return; + } + String next = jp.next(); + if (!source.containsKey(next)) + { + // reached end of branch in source before end of specified json path - + // the specified path is illegal because it does not exist in the source. + action.handlePrematureNavigatedBranchEnd(jp, source); + } + else if (source.get(next) instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) source.get(next))) + { + //reached JSONObject node - handle it and recur into it + nav((JSONObject) source.get(next), jp); + } + else if (source.get(next) instanceof JSONArray && action.handleJSONArrray(jp, (JSONArray) source.get(next))) + { + //reached JSONArray node - handle it and recur into it + nav((JSONArray) source.get(next), jp); + } + else if (jp.hasNext()) + { + // reached leaf node (not a container) in source but specified path expects children - + // the specified path is illegal because it does not exist in the source. + action.handlePrematureNavigatedBranchEnd(jp, source.get(next)); + } + else if (!jp.hasNext()) + { + //reached leaf in source and specified path is also at leaf -> handle it + action.handleJSONObjectLeaf(jp, source.get(next)); + } + else + { + throw new IllegalStateException("fatal: unreachable code reached at '" + jp.origin() + "'"); + } + } + action.handleObjectEnd(jp); + } + + private void nav(JSONArray source, TreePath jp) + { + if (source == null) + { + //array is null - navigation impossible + return; + } + int arrIndex = 0; + for (Object arrItem : source.toArray()) + { + if (arrItem instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) arrItem)) + { + // clone the path so that for each JSONObject in the array, + // the iterator continues from the same position in the path + TreePath jpClone = getClone(jp); + nav((JSONObject) arrItem, jpClone); + } + else if (arrItem instanceof JSONArray) + { + throw new IllegalArgumentException("illegal json - found array nested inside array at: '" + jp.origin() + "'"); + } + else if (!jp.hasNext()) + { + //reached leaf - handle it + action.handleJSONArrayLeaf(arrIndex, arrItem); + } + arrIndex++; + } + action.handleJSONArrayEnd(jp); + + } + + private TreePath getClone(TreePath jp) + { + try + { + return jp.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException("failed to clone json path", e); + } + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java index eddf5438..0d2059b4 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java @@ -1,100 +1,100 @@ package net.minidev.json.actions.navigate; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.JSONPath; +import net.minidev.json.actions.path.TreePath; import java.util.Collection; +import java.util.List; +import java.util.Map; /** - * An interface for a processing action on the nodes of a {@link JSONObject} while navigating its branches. + * An interface for a processing action on the nodes of a {@link M} while navigating its branches. *

* See package-info for more details * * @author adoneitan@gmail.com */ -public interface NavigateAction +public interface NavigateAction, L extends List> { /** - * called before any navigation of the {@link JSONObject} starts + * called before any navigation of the {@link M} starts * @return true if navigation should start at all */ - boolean handleNavigationStart(JSONObject objectToNavigate, Collection pathsToNavigate); + boolean start(M objectToNavigate, Collection pathsToNavigate); /** * called before navigation of a new path starts * @return true if the specified path should be navigated */ - boolean handleNextPath(String path); + boolean pathStart(String path); /** * reached end of branch in source before end of specified json path - * the specified path does not exist in the source. */ - void handlePrematureNavigatedBranchEnd(JSONPath jp, Object source); + void handlePrematureNavigatedBranchEnd(TreePath tp, Object source); /** * called after the navigation of a path ends */ - void handlePathEnd(String path); + void pathEnd(String path); /** * called if navigation of a path throws an exception * @return true if the failure on this path should not abort the rest of the navigation */ - boolean failPathSilently(String path, Exception e); + boolean failSilently(String path, Exception e); /** * called if navigation of a path throws an exception * @return true if the failure on this path should abort the rest of the navigation */ - boolean failPathFast(String path, Exception e); + boolean failFast(String path, Exception e); /** * called when an object node is encountered on the path * @return true if the navigator should navigate into the object */ - boolean handleJSONObject(JSONPath jp, JSONObject sourceNode); + boolean recurInto(TreePath tp, M sourceNode); /** * called when an array node is encountered on the path * @return true if the navigator should navigate into the array */ - boolean handleJSONArrray(JSONPath jp, JSONArray sourceNode); + boolean recurInto(TreePath tp, L sourceNode); /** - * called when a leaf node is reached in a JSONObject. - * a leaf in a JSONObject is a key-value pair where the value is not a container itself - * (it is not a JSONObject nor a JSONArray) - * @param jp - the JsonPath pointing to the leaf + * called when a leaf node is reached in a M. + * a leaf in a M is a key-value pair where the value is not a container itself + * (it is not a M nor a L) + * @param tp - the JsonPath pointing to the leaf */ - void handleJSONObjectLeaf(JSONPath jp, Object value); + void handleLeaf(TreePath tp, Object value); /** - * called when a leaf in a JSONArray is reached. - * a leaf in a JSONArray is a non-container item - * (it is not a JSONObject nor a JSONArray) - * @param arrIndex - the index of the item in the JSONArray + * called when a leaf in a L is reached. + * a leaf in a L is a non-container item + * (it is not a M nor a L) + * @param arrIndex - the index of the item in the L * @param arrItem - the item */ - void handleJSONArrayLeaf(int arrIndex, Object arrItem); + void handleLeaf(TreePath tp, int arrIndex, Object arrItem); /** - * called after all the items of an array have been visited - * @param jp - the JsonPath pointing to the array + * called when navigation of an {@link M} type object ends + * @param tp the path pointing to the object */ - void handleJSONArrayEnd(JSONPath jp); + void recurEnd(TreePath tp, M m); /** - * called after all the entries of a JSONObject have been visited - * @param jp - the JsonPath pointing to the object + * called when navigation of an {@link L} type object ends + * @param tp the path pointing to the object */ - void handleObjectEnd(JSONPath jp); + void recurEnd(TreePath tp, L l); /** * called after all navigation ends, and just before the navigation method exits */ - void handleNavigationEnd(); + void end(); /** * holds the result of the navigation, as assigned by the action implementing this interface diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java new file mode 100755 index 00000000..48274fa8 --- /dev/null +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java @@ -0,0 +1,171 @@ +package net.minidev.json.actions.navigate; + +import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.TreePath; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * Navigates only the branches of a {@link JSONObject} corresponding to the paths specified. + *

+ * For each specified path to navigate, the {@link TreeNavigator} only traverses the matching + * branch. + *

+ * The navigator accepts an action and provides callback hooks for it to act on the traversed + * nodes at each significant step. See {@link NavigateAction}. + *

+ * See package-info for more details + *

+ * Example: + *

+ * To navigate the branch k1.k2 of the object {"k1":{"k2":"v1"}, "k3":{"k4":"v2"}} instantiate + * the navigator like so: new JSONNavigator("k1.k2") + * + * @author adoneitan@gmail.com + * + */ +public class TreeNavigator, L extends List> +{ + protected List pathsToNavigate; + protected NavigateAction action; + protected String pathPrefix = ""; + + public TreeNavigator(NavigateAction action, List pathsToNavigate) + { + if (action == null) { + throw new IllegalArgumentException("NavigateAction cannot be null"); + } + this.action = action; + this.pathsToNavigate = pathsToNavigate; + } + + public TreeNavigator with(String pathPrefix) { + this.pathPrefix = pathPrefix; + return this; + } + + public TreeNavigator(NavigateAction action, String... pathsToNavigate) + { + this(action, Arrays.asList(pathsToNavigate)); + } + + public void nav(M object) throws Exception + { + if (action.start(object, pathsToNavigate)) + { + for (String path: pathsToNavigate) + { + try + { + if (path != null && !path.equals("") && action.pathStart(path)) + { + TreePath jp = new TreePath(path, new DotDelimiter().withAcceptDelimiterInNodeName(true)); + nav(jp, object); + action.pathEnd(path); + } + } + catch (Exception e) + { + if (action.failSilently(path ,e)) { + break; + } + else if (action.failFast(path, e)) { + throw e; + } + } + } + } + action.end(); + } + + private void nav(TreePath jp, M map) + { + if (map == null || !action.recurInto(jp, map)) + { + //source is null - navigation impossible + return; + } + + if (jp.hasNext()) + { + String key = jp.next(); + if (!map.containsKey(key)) + { + // reached end of branch in source before end of specified json path - + // the specified path is illegal because it does not exist in the source. + action.handlePrematureNavigatedBranchEnd(jp, map); + } + else if (map.get(key) instanceof Map) + { + //reached Map type node - handle it and recur into it + nav(jp, (M) map.get(key)); + } + else if (map.get(key) instanceof List) + { + //reached List type node - handle it and recur into it + nav(jp, (L) map.get(key)); + } + else if (jp.hasNext()) + { + // reached leaf node (not a container) in source but specified path expects children - + // the specified path is illegal because it does not exist in the source. + action.handlePrematureNavigatedBranchEnd(jp, map.get(key)); + } + else if (!jp.hasNext()) + { + //reached leaf in source and specified path is also at leaf -> handle it + action.handleLeaf(jp, map.get(key)); + } + else + { + throw new IllegalStateException("fatal: unreachable code reached at '" + jp.origin() + "'"); + } + } + action.recurEnd(jp, (M) map); + } + + private void nav(TreePath jp, L list) + { + if (list == null || !action.recurInto(jp, (L) list)) + { + //list is null - navigation impossible + return; + } + int arrIndex = 0; + for (Object arrItem : list.toArray()) + { + if (arrItem instanceof Map) + { + // clone the path so that for each object in the array, + // the iterator continues from the same position in the path + TreePath jpClone = getClone(jp); + nav(jpClone, (M) arrItem); + } + else if (arrItem instanceof List) + { + nav(jp, (L) arrItem); + } + else if (!jp.hasNext()) + { + //reached leaf - handle it + action.handleLeaf(jp, arrIndex, arrItem); + } + arrIndex++; + } + action.recurEnd(jp, (L) list); + } + + private TreePath getClone(TreePath jp) + { + try + { + return jp.clone(); + } + catch (CloneNotSupportedException e) { + throw new RuntimeException("failed to clone path", e); + } + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java index 537cf36e..fef786e1 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java @@ -1,10 +1,10 @@ /** * Navigate user-specified paths in a {@link net.minidev.json.JSONObject} and process them *

- * {@link net.minidev.json.actions.navigate.JSONNavigator} only navigates through branches corresponding + * {@link net.minidev.json.actions.navigate.JSONNavigatorOld} only navigates through branches corresponding * to user-specified paths. For each path, the navigation starts at the root and moves down the branch. *

- * The {@link net.minidev.json.actions.navigate.JSONNavigator} accepts a + * The {@link net.minidev.json.actions.navigate.JSONNavigatorOld} accepts a * {@link net.minidev.json.actions.navigate.NavigateAction} and provides callback hooks at each significant * step which the {@link net.minidev.json.actions.navigate.NavigateAction} may use to process * the nodes. diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/JSONPath.java b/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java similarity index 87% rename from json-smart/src/main/java/net/minidev/json/actions/path/JSONPath.java rename to json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java index 2ab7d85a..a2d4f0bd 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/path/JSONPath.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java @@ -1,21 +1,21 @@ package net.minidev.json.actions.path; -import net.minidev.json.JSONObject; - import java.util.Arrays; +import java.util.Map; import java.util.List; import java.util.ListIterator; /** - * {@link JSONPath} represents an n-gram formatted path - * corresponding to a branch in a {@link JSONObject} + * {@link TreePath} represents an n-gram formatted path + * corresponding to a branch in a tree of {@link Map}s + * and {@link List}s *

* See package-info for more details * * @author adoneitan@gmail.com */ -public class JSONPath +public class TreePath { protected enum Step {NONE, NEXT, PREV} @@ -28,7 +28,7 @@ protected enum Step {NONE, NEXT, PREV} protected StringBuilder remainder; protected PathDelimiter delim; - public JSONPath(String path, PathDelimiter delim) + public TreePath(String path, PathDelimiter delim) { this.delim = delim; checkPath(path); @@ -197,9 +197,9 @@ private void checkPath(String path) } @Override - public JSONPath clone() throws CloneNotSupportedException + public TreePath clone() throws CloneNotSupportedException { - JSONPath cloned = new JSONPath(this.path, this.delim); + TreePath cloned = new TreePath(this.path, this.delim); while (cloned.nextIndex() != this.nextIndex()) { cloned.next(); } @@ -218,16 +218,16 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - JSONPath jsonPath = (JSONPath) o; + TreePath treePath = (TreePath) o; - return path().equals(jsonPath.path()) && - hasNext() == jsonPath.hasNext() && - hasPrev() == jsonPath.hasPrev() && - curr().equals(jsonPath.curr()) && - origin().equals(jsonPath.origin()) && - remainder().equals(jsonPath.remainder()) && - lastStep == jsonPath.lastStep && - delim.equals(jsonPath.delim); + return path().equals(treePath.path()) && + hasNext() == treePath.hasNext() && + hasPrev() == treePath.hasPrev() && + curr().equals(treePath.curr()) && + origin().equals(treePath.origin()) && + remainder().equals(treePath.remainder()) && + lastStep == treePath.lastStep && + delim.equals(treePath.delim); } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java index 89b78fe5..39fbbfcf 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java @@ -20,8 +20,9 @@ */ public class TreeTraverser, L extends List> { - protected PathDelimiter delim; protected TreeTraverseAction action; + protected PathDelimiter delim; + protected String pathPrefix = ""; public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) { @@ -29,24 +30,29 @@ public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) this.delim = delim; } + public TreeTraverser with(String pathPrefix) { + this.pathPrefix = pathPrefix; + return this; + } + public void traverse(M map) { if (action.start(map)){ - depthFirst("", map); + depthFirst(pathPrefix, map); } action.end(); } - private void depthFirst(String fullPathToMap, M map) + private void depthFirst(String fullPath, M map) { - if (map == null || map.entrySet() == null || !action.recurInto(fullPathToMap, map)) { + if (map == null || map.entrySet() == null || !action.recurInto(fullPath, map)) { return; } Iterator> it = map.entrySet().iterator(); while (it.hasNext()) { Entry entry = it.next(); - String fullPathToEntry = buildPath(fullPathToMap, entry.getKey()); + String fullPathToEntry = buildPath(fullPath, entry.getKey()); if (!action.traverseEntry(fullPathToEntry, entry)) { continue; @@ -57,11 +63,11 @@ else if (action.removeEntry(fullPathToEntry, entry)) continue; } - if (instanceOfMap(entry.getValue())) + if (entry.getValue() instanceof Map) { depthFirst(fullPathToEntry, (M) entry.getValue()); } - else if (instanceOfList(entry.getValue())) + else if (entry.getValue() instanceof List) { depthFirst(fullPathToEntry, (L) entry.getValue()); } @@ -72,39 +78,32 @@ else if (instanceOfList(entry.getValue())) } } - private void depthFirst(String fullPathToList, L list) + private void depthFirst(String fullPath, L list) { - if (!action.recurInto(fullPathToList, (L) list)) { + if (!action.recurInto(fullPath, (L) list)) { return; } int listIndex = 0; for (Object listItem : list.toArray()) { - if (instanceOfMap(listItem)) + if (listItem instanceof Map) { - depthFirst(fullPathToList, (M) listItem); + depthFirst(fullPath, (M) listItem); } - else if (instanceOfList(listItem)) + else if (listItem instanceof List) { - depthFirst(fullPathToList, (L) listItem); + depthFirst(fullPath, (L) listItem); } else { - action.handleLeaf(fullPathToList, listIndex, listItem); + action.handleLeaf(fullPath, listIndex, listItem); } listIndex++; } } - private String buildPath(String fullPathToObject, String entryKey) { - return "".equals(fullPathToObject) ? entryKey : fullPathToObject + delim.str() + entryKey; + private String buildPath(String fullPath, String entryKey) { + return pathPrefix.equals(fullPath) ? pathPrefix + entryKey : fullPath + delim.str() + entryKey; } - private boolean instanceOfList(Object obj) { - return obj instanceof List; - } - - private boolean instanceOfMap(Object obj) { - return obj instanceof Map; - } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java similarity index 87% rename from json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java rename to json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java index 4fae7f60..876bfb3f 100755 --- a/json-smart/src/test/java/net/minidev/json/test/actions/JSONPathTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java @@ -1,7 +1,7 @@ package net.minidev.json.test.actions; import net.minidev.json.actions.path.DotDelimiter; -import net.minidev.json.actions.path.JSONPath; +import net.minidev.json.actions.path.TreePath; import net.minidev.json.actions.path.PathDelimiter; import org.junit.Test; @@ -11,14 +11,14 @@ /** * @author adoneitan@gmail.com */ -public class JSONPathTest +public class TreePathTest { private static final PathDelimiter delim = new DotDelimiter().withAcceptDelimiterInNodeName(true); @Test public void testIterator() { - JSONPath jp = new JSONPath("a.b.c", delim); + TreePath jp = new TreePath("a.b.c", delim); assertTrue(jp.nextIndex() == 0); assertTrue(jp.prevIndex() == -1); assertTrue("".equals(jp.curr())); @@ -74,23 +74,23 @@ public void testIterator() @Test public void testSubPath() { - JSONPath jp = new JSONPath("a.b.c", delim); + TreePath jp = new TreePath("a.b.c", delim); assertTrue(jp.subPath(1,2).equals("b.c")); } @Test public void testClone() throws CloneNotSupportedException { - JSONPath jp1 = new JSONPath("a.b.c", delim); - JSONPath jp2 = jp1.clone(); + TreePath jp1 = new TreePath("a.b.c", delim); + TreePath jp2 = jp1.clone(); assertTrue(jp1.equals(jp2)); jp1.next(); - JSONPath jp3 = jp1.clone(); + TreePath jp3 = jp1.clone(); assertTrue(jp1.equals(jp3)); jp1.prev(); - JSONPath jp4 = jp1.clone(); + TreePath jp4 = jp1.clone(); assertTrue(jp1.equals(jp4)); } From 1649130966ab907557eeea7c24fff72894308ea3 Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Sun, 19 Jun 2016 21:10:01 +0300 Subject: [PATCH 09/18] house cleaning --- .../minidev/json/actions/PathReplicator.java | 1 + .../actions/navigate/CopyPathsAction.java | 1 + .../actions/navigate/JSONNavigateAction.java | 1 + .../navigate/JSONNavigateActionOld.java | 103 ---------- .../json/actions/navigate/JSONNavigator.java | 3 +- .../actions/navigate/JSONNavigatorOld.java | 191 ------------------ .../json/actions/navigate/NavigateAction.java | 13 +- .../json/actions/navigate/TreeNavigator.java | 1 + .../json/actions/navigate/package-info.java | 6 +- 9 files changed, 16 insertions(+), 304 deletions(-) delete mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java delete mode 100755 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java index b708374f..65173a35 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java @@ -34,6 +34,7 @@ * see unit tests for more examples * * @author adoneitan@gmail.com + * @since 15 March 2016. */ public class PathReplicator { diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java index 42d0797c..252c5659 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -25,6 +25,7 @@ * See unit tests for more examples * * @author adoneitan@gmail.com + * @since 15 March 2016. * */ public class CopyPathsAction implements JSONNavigateAction diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java index eff79f8d..8c1adb8a 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java @@ -9,6 +9,7 @@ * See package-info for more details * * @author adoneitan@gmail.com + * @since 15 June 2016. */ public interface JSONNavigateAction extends NavigateAction { diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java deleted file mode 100755 index c46aa5fe..00000000 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateActionOld.java +++ /dev/null @@ -1,103 +0,0 @@ -package net.minidev.json.actions.navigate; - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.TreePath; - -import java.util.Collection; - -/** - * An interface for a processing action on the nodes of a {@link JSONObject} while navigating its branches. - *

- * See package-info for more details - * - * @author adoneitan@gmail.com - */ -public interface JSONNavigateActionOld -{ - /** - * called before any navigation of the {@link JSONObject} starts - * @return true if navigation should start at all - */ - boolean handleNavigationStart(JSONObject objectToNavigate, Collection pathsToNavigate); - - /** - * called before navigation of a new path starts - * @return true if the specified path should be navigated - */ - boolean handleNextPath(String path); - - /** - * reached end of branch in source before end of specified json path - - * the specified path does not exist in the source. - */ - void handlePrematureNavigatedBranchEnd(TreePath jp, Object source); - - /** - * called after the navigation of a path ends - */ - void handlePathEnd(String path); - - /** - * called if navigation of a path throws an exception - * @return true if the failure on this path should not abort the rest of the navigation - */ - boolean failPathSilently(String path, Exception e); - - /** - * called if navigation of a path throws an exception - * @return true if the failure on this path should abort the rest of the navigation - */ - boolean failPathFast(String path, Exception e); - - /** - * called when an object node is encountered on the path - * @return true if the navigator should navigate into the object - */ - boolean handleJSONObject(TreePath jp, JSONObject sourceNode); - - /** - * called when an array node is encountered on the path - * @return true if the navigator should navigate into the array - */ - boolean handleJSONArrray(TreePath jp, JSONArray sourceNode); - - /** - * called when a leaf node is reached in a JSONObject. - * a leaf in a JSONObject is a key-value pair where the value is not a container itself - * (it is not a JSONObject nor a JSONArray) - * @param jp - the JsonPath pointing to the leaf - */ - void handleJSONObjectLeaf(TreePath jp, Object value); - - /** - * called when a leaf in a JSONArray is reached. - * a leaf in a JSONArray is a non-container item - * (it is not a JSONObject nor a JSONArray) - * @param arrIndex - the index of the item in the JSONArray - * @param arrItem - the item - */ - void handleJSONArrayLeaf(int arrIndex, Object arrItem); - - /** - * called after all the items of an array have been visited - * @param jp - the JsonPath pointing to the array - */ - void handleJSONArrayEnd(TreePath jp); - - /** - * called after all the entries of a JSONObject have been visited - * @param jp - the JsonPath pointing to the object - */ - void handleObjectEnd(TreePath jp); - - /** - * called after all navigation ends, and just before the navigation method exits - */ - void handleNavigationEnd(); - - /** - * holds the result of the navigation, as assigned by the action implementing this interface - */ - Object result(); -} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java index 4030be92..3a366c21 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java @@ -6,7 +6,8 @@ import java.util.List; /** - * Created by eitanraviv on 6/15/16. + * @author adoneitan@gmail.com + * @since 15 June 2016. */ public class JSONNavigator extends TreeNavigator { diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java deleted file mode 100755 index 2b4467f9..00000000 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigatorOld.java +++ /dev/null @@ -1,191 +0,0 @@ -package net.minidev.json.actions.navigate; - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.DotDelimiter; -import net.minidev.json.actions.path.TreePath; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; - -/** - * Navigates only the branches of a {@link JSONObject} corresponding to the paths specified. - *

- * For each specified path to navigate, the {@link JSONNavigatorOld} only traverses the matching - * branch. - *

- * The navigator accepts an action and provides callback hooks for it to act on the traversed - * nodes at each significant step. See {@link JSONNavigateActionOld}. - *

- * See package-info for more details - *

- * Example: - *

- * To navigate the branch k1.k2 of the object {"k1":{"k2":"v1"}, "k3":{"k4":"v2"}} instantiate - * the navigator like so: new JSONNavigator("k1.k2") - * - * @author adoneitan@gmail.com - * - */ -public class JSONNavigatorOld -{ - protected List pathsToNavigate; - protected JSONNavigateActionOld action; - - public JSONNavigatorOld(JSONNavigateActionOld action, JSONArray pathsToNavigate) - { - if (action == null) { - throw new IllegalArgumentException("JSONNavigateActionOld cannot be null"); - } - this.action = action; - if (pathsToNavigate == null || pathsToNavigate.isEmpty()) { - this.pathsToNavigate = Collections.emptyList(); - } - else - { - this.pathsToNavigate = new LinkedList(); - for (Object s : pathsToNavigate) { - this.pathsToNavigate.add((String) s); - } - } - } - - public JSONNavigatorOld(JSONNavigateActionOld action, List pathsToNavigate) - { - if (action == null) { - throw new IllegalArgumentException("JSONNavigateActionOld cannot be null"); - } - this.action = action; - this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.size() == 0 ? - Collections.emptyList() : pathsToNavigate; - } - - public JSONNavigatorOld(JSONNavigateActionOld action, String... pathsToNavigate) - { - if (action == null) { - throw new IllegalArgumentException("JSONNavigateActionOld cannot be null"); - } - this.action = action; - this.pathsToNavigate = pathsToNavigate == null || pathsToNavigate.length == 0 ? - Collections.emptyList() : new LinkedList(Arrays.asList(pathsToNavigate)); - } - - public void nav(JSONObject object) throws Exception - { - if (action.handleNavigationStart(object, pathsToNavigate)) - { - for (String path: pathsToNavigate) - { - try - { - if (path != null && !path.equals("") && action.handleNextPath(path)) - { - TreePath jp = new TreePath(path, new DotDelimiter().withAcceptDelimiterInNodeName(true)); - nav(object, jp); - action.handlePathEnd(path); - } - } - catch (Exception e) - { - if (action.failPathSilently(path ,e)) { - break; - } - else if (action.failPathFast(path, e)) { - throw e; - } - } - } - } - action.handleNavigationEnd(); - } - - private void nav(JSONObject source, TreePath jp) - { - if (jp.hasNext()) - { - if (source == null) - { - //source is null - navigation impossible - return; - } - String next = jp.next(); - if (!source.containsKey(next)) - { - // reached end of branch in source before end of specified json path - - // the specified path is illegal because it does not exist in the source. - action.handlePrematureNavigatedBranchEnd(jp, source); - } - else if (source.get(next) instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) source.get(next))) - { - //reached JSONObject node - handle it and recur into it - nav((JSONObject) source.get(next), jp); - } - else if (source.get(next) instanceof JSONArray && action.handleJSONArrray(jp, (JSONArray) source.get(next))) - { - //reached JSONArray node - handle it and recur into it - nav((JSONArray) source.get(next), jp); - } - else if (jp.hasNext()) - { - // reached leaf node (not a container) in source but specified path expects children - - // the specified path is illegal because it does not exist in the source. - action.handlePrematureNavigatedBranchEnd(jp, source.get(next)); - } - else if (!jp.hasNext()) - { - //reached leaf in source and specified path is also at leaf -> handle it - action.handleJSONObjectLeaf(jp, source.get(next)); - } - else - { - throw new IllegalStateException("fatal: unreachable code reached at '" + jp.origin() + "'"); - } - } - action.handleObjectEnd(jp); - } - - private void nav(JSONArray source, TreePath jp) - { - if (source == null) - { - //array is null - navigation impossible - return; - } - int arrIndex = 0; - for (Object arrItem : source.toArray()) - { - if (arrItem instanceof JSONObject && action.handleJSONObject(jp, (JSONObject) arrItem)) - { - // clone the path so that for each JSONObject in the array, - // the iterator continues from the same position in the path - TreePath jpClone = getClone(jp); - nav((JSONObject) arrItem, jpClone); - } - else if (arrItem instanceof JSONArray) - { - throw new IllegalArgumentException("illegal json - found array nested inside array at: '" + jp.origin() + "'"); - } - else if (!jp.hasNext()) - { - //reached leaf - handle it - action.handleJSONArrayLeaf(arrIndex, arrItem); - } - arrIndex++; - } - action.handleJSONArrayEnd(jp); - - } - - private TreePath getClone(TreePath jp) - { - try - { - return jp.clone(); - } - catch (CloneNotSupportedException e) { - throw new RuntimeException("failed to clone json path", e); - } - } -} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java index 0d2059b4..fbb8361e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java @@ -12,21 +12,22 @@ * See package-info for more details * * @author adoneitan@gmail.com + * @since 15 June 2016 */ public interface NavigateAction, L extends List> { - /** - * called before any navigation of the {@link M} starts - * @return true if navigation should start at all - */ - boolean start(M objectToNavigate, Collection pathsToNavigate); - /** * called before navigation of a new path starts * @return true if the specified path should be navigated */ boolean pathStart(String path); + /** + * called before any navigation of the {@link M} starts + * @return true if navigation should start at all + */ + boolean start(M objectToNavigate, Collection pathsToNavigate); + /** * reached end of branch in source before end of specified json path - * the specified path does not exist in the source. diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java index 48274fa8..bcd4e304 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java @@ -25,6 +25,7 @@ * the navigator like so: new JSONNavigator("k1.k2") * * @author adoneitan@gmail.com + * @since 15 June 2016. * */ public class TreeNavigator, L extends List> diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java index fef786e1..40727e40 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java @@ -1,10 +1,10 @@ /** - * Navigate user-specified paths in a {@link net.minidev.json.JSONObject} and process them + * Navigate user-specified paths in a tree made up of {@link java.util.Map}s and {@link java.util.List} and process them *

- * {@link net.minidev.json.actions.navigate.JSONNavigatorOld} only navigates through branches corresponding + * {@link net.minidev.json.actions.navigate.TreeNavigator} only navigates through branches corresponding * to user-specified paths. For each path, the navigation starts at the root and moves down the branch. *

- * The {@link net.minidev.json.actions.navigate.JSONNavigatorOld} accepts a + * The {@link net.minidev.json.actions.navigate.TreeNavigator} accepts a * {@link net.minidev.json.actions.navigate.NavigateAction} and provides callback hooks at each significant * step which the {@link net.minidev.json.actions.navigate.NavigateAction} may use to process * the nodes. From ad93cc532a7b0ad45aaf7633eacf5539ff61deb7 Mon Sep 17 00:00:00 2001 From: "adoneitan@gmail.com" Date: Tue, 21 Jun 2016 06:43:49 +0300 Subject: [PATCH 10/18] finalize tree navigator --- .../net/minidev/json/actions/JSONBuilder.java | 17 ----------------- .../json/actions/navigate/CopyPathsAction.java | 13 ++++++------- .../json/actions/navigate/NavigateAction.java | 13 ++++++++++--- .../json/actions/navigate/TreeNavigator.java | 12 ++++++------ .../actions}/KeysPrintActionTest.java | 4 +++- 5 files changed, 25 insertions(+), 34 deletions(-) delete mode 100644 json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java rename json-smart/src/test/java/net/minidev/json/{actions/traverse => test/actions}/KeysPrintActionTest.java (84%) diff --git a/json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java b/json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java deleted file mode 100644 index 23e65245..00000000 --- a/json-smart/src/main/java/net/minidev/json/actions/JSONBuilder.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.minidev.json.actions; - -import net.minidev.json.JSONObject; - -/** - * @author adoneitan@gmail.com - * @since 14 June 2016 - */ -public class JSONBuilder -{ - protected JSONObject result; - - public void append(String path, String value) - { - - } -} diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java index 252c5659..52d5df7e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -42,16 +42,10 @@ public boolean start(JSONObject source, Collection pathsToCopy) destTree = null; return false; } - destTree = new JSONObject(); if (pathsToCopy == null || pathsToCopy.size() == 0) { return false; } - - /** - * using ARRAY_PUSH which adds any new entry encountered in arrays, effectively - * allowing duplicate objects in the array, which is supported by Gigya - */ return true; } @@ -86,10 +80,15 @@ public boolean recurInto(TreePath jp, JSONArray o) } @Override - public void handlePrematureNavigatedBranchEnd(TreePath jp, Object source) { + public void foundLeafBeforePathEnd(TreePath jp, Object obj) { throw new IllegalArgumentException("branch is shorter than path - path not found in source: '" + jp.origin() + "'"); } + @Override + public void pathTailNotFound(TreePath jp, Object source) { + throw new IllegalArgumentException("cannot find next element of path - path not found in source: '" + jp.origin() + "'"); + } + @Override public void handleLeaf(TreePath jp, Object o) { ((JSONObject) destNodeStack.peek()).put(jp.curr(), o); diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java index fbb8361e..51195e1a 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java @@ -29,10 +29,10 @@ public interface NavigateAction, L extends List pathsToNavigate); /** - * reached end of branch in source before end of specified json path - - * the specified path does not exist in the source. + * reached end of branch in source before end of specified path - + * the specified path does not exist in the source */ - void handlePrematureNavigatedBranchEnd(TreePath tp, Object source); + void pathTailNotFound(TreePath tp, Object source); /** * called after the navigation of a path ends @@ -63,6 +63,12 @@ public interface NavigateAction, L extends List, L extends List Date: Fri, 23 Sep 2016 19:21:23 -0700 Subject: [PATCH 11/18] Setp 1 unify code format + fix invalide java filename --- .../main/java/net/minidev/json/JSONStyle.java | 6 +- .../minidev/json/actions/ElementRemover.java | 16 ++-- .../net/minidev/json/actions/PathRemover.java | 25 ++--- .../minidev/json/actions/PathReplicator.java | 26 ++--- .../minidev/json/actions/PathsRetainer.java | 28 ++---- .../actions/navigate/CopyPathsAction.java | 24 ++--- .../actions/navigate/JSONNavigateAction.java | 3 +- .../json/actions/navigate/JSONNavigator.java | 9 +- .../json/actions/navigate/NavigateAction.java | 5 +- .../json/actions/navigate/TreeNavigator.java | 94 ++++++------------- .../json/actions/path/DotDelimiter.java | 9 +- .../json/actions/path/PathDelimiter.java | 9 +- .../json/actions/path/SlashDelimiter.java | 9 +- .../minidev/json/actions/path/TreePath.java | 64 +++++-------- .../actions/traverse/JSONTraverseAction.java | 3 +- .../json/actions/traverse/JSONTraverser.java | 6 +- .../actions/traverse/KeysPrintAction.java | 24 ++--- .../traverse/LocatePathsJSONAction.java | 29 +++--- .../traverse/RemoveElementsJSONAction.java | 29 ++---- .../traverse/RemovePathsJsonAction.java | 25 ++--- .../actions/traverse/TreeTraverseAction.java | 3 +- .../json/actions/traverse/TreeTraverser.java | 49 +++------- .../json/actions/traverse/package-info.java | 1 - .../net/minidev/json/annotate/JsonIgnore.java | 2 - 24 files changed, 169 insertions(+), 329 deletions(-) diff --git a/json-smart/src/main/java/net/minidev/json/JSONStyle.java b/json-smart/src/main/java/net/minidev/json/JSONStyle.java index fbd3f715..a575c75f 100644 --- a/json-smart/src/main/java/net/minidev/json/JSONStyle.java +++ b/json-smart/src/main/java/net/minidev/json/JSONStyle.java @@ -106,7 +106,7 @@ public boolean protectValues() { public boolean protect4Web() { return _protect4Web; } - + public boolean ignoreNull() { return _ignore_null; } @@ -122,7 +122,7 @@ public boolean mustProtectKey(String s) { public boolean mustProtectValue(String s) { return mpValue.mustBeProtect(s); } - + public void writeString(Appendable out, String value) throws IOException { if (!this.mustProtectValue(value)) out.append(value); @@ -136,7 +136,7 @@ public void writeString(Appendable out, String value) throws IOException { public void escape(String s, Appendable out) { esc.escape(s, out); } - + /** * begin Object */ diff --git a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java index c501b58e..663b6e26 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java +++ b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java @@ -26,22 +26,18 @@ * @author adoneitan@gmail.com * */ -public class ElementRemover -{ +public class ElementRemover { private Map elementsToRemove; - public ElementRemover(Map elementsToRemove) - { - this.elementsToRemove = elementsToRemove == null ? Collections.emptyMap() : elementsToRemove; + public ElementRemover(Map elementsToRemove) { + this.elementsToRemove = elementsToRemove == null ? Collections. emptyMap() : elementsToRemove; } - public ElementRemover(JSONObject elementsToRemove) - { - this.elementsToRemove = elementsToRemove == null ? Collections.emptyMap() : elementsToRemove; + public ElementRemover(JSONObject elementsToRemove) { + this.elementsToRemove = elementsToRemove == null ? Collections. emptyMap() : elementsToRemove; } - public JSONObject remove(JSONObject objectToClean) - { + public JSONObject remove(JSONObject objectToClean) { JSONTraverseAction strategy = new RemoveElementsJsonAction(this.elementsToRemove); JSONTraverser traversal = new JSONTraverser(strategy); traversal.traverse(objectToClean); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java index c8c4db37..f872445c 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java @@ -34,17 +34,13 @@ * @author adoneitan@gmail.com * */ -public class PathRemover -{ +public class PathRemover { protected List pathsToRemove; - public PathRemover(JSONArray pathsToRemove) - { + public PathRemover(JSONArray pathsToRemove) { if (pathsToRemove == null || pathsToRemove.isEmpty()) { this.pathsToRemove = Collections.emptyList(); - } - else - { + } else { this.pathsToRemove = new ArrayList(); for (Object s : pathsToRemove) { this.pathsToRemove.add((String) s); @@ -52,20 +48,15 @@ public PathRemover(JSONArray pathsToRemove) } } - public PathRemover(List pathsToRemove) - { - this.pathsToRemove = pathsToRemove == null || pathsToRemove.size() == 0 ? - Collections.emptyList() : pathsToRemove; + public PathRemover(List pathsToRemove) { + this.pathsToRemove = pathsToRemove == null || pathsToRemove.size() == 0 ? Collections. emptyList() : pathsToRemove; } - public PathRemover(String... pathsToRemove) - { - this.pathsToRemove = pathsToRemove == null || pathsToRemove.length == 0 ? - Collections.emptyList() : Arrays.asList(pathsToRemove); + public PathRemover(String... pathsToRemove) { + this.pathsToRemove = pathsToRemove == null || pathsToRemove.length == 0 ? Collections. emptyList() : Arrays.asList(pathsToRemove); } - public JSONObject remove(JSONObject objectToClean) - { + public JSONObject remove(JSONObject objectToClean) { JSONTraverseAction strategy = new RemovePathsJsonAction(this.pathsToRemove); JSONTraverser traversal = new JSONTraverser(strategy); traversal.traverse(objectToClean); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java index 65173a35..3841c946 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java @@ -36,17 +36,13 @@ * @author adoneitan@gmail.com * @since 15 March 2016. */ -public class PathReplicator -{ +public class PathReplicator { protected List pathsToCopy; - public PathReplicator(JSONArray pathsToCopy) - { + public PathReplicator(JSONArray pathsToCopy) { if (pathsToCopy == null || pathsToCopy.isEmpty()) { this.pathsToCopy = Collections.emptyList(); - } - else - { + } else { this.pathsToCopy = new LinkedList(); for (Object s : pathsToCopy) { this.pathsToCopy.add((String) s); @@ -54,20 +50,16 @@ public PathReplicator(JSONArray pathsToCopy) } } - public PathReplicator(List pathsToCopy) - { - this.pathsToCopy = pathsToCopy == null || pathsToCopy.size() == 0 ? - Collections.emptyList() : pathsToCopy; + public PathReplicator(List pathsToCopy) { + this.pathsToCopy = pathsToCopy == null || pathsToCopy.size() == 0 ? Collections. emptyList() : pathsToCopy; } - public PathReplicator(String... pathsToCopy) - { - this.pathsToCopy = pathsToCopy == null || pathsToCopy.length == 0 ? - Collections.emptyList() : new LinkedList(Arrays.asList(pathsToCopy)); + public PathReplicator(String... pathsToCopy) { + this.pathsToCopy = pathsToCopy == null || pathsToCopy.length == 0 ? Collections. emptyList() + : new LinkedList(Arrays.asList(pathsToCopy)); } - public JSONObject replicate(JSONObject sourceObj) throws Exception - { + public JSONObject replicate(JSONObject sourceObj) throws Exception { CopyPathsAction s = new CopyPathsAction(); JSONNavigator n = new JSONNavigator(s, pathsToCopy); n.nav(sourceObj); diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java index f4fa2496..e641ec2e 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java @@ -33,18 +33,14 @@ * * @author adoneitan@gmail.com */ -public class PathsRetainer -{ +public class PathsRetainer { protected List pathsToRetain; protected PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); - public PathsRetainer(JSONArray pathsToRetain) - { + public PathsRetainer(JSONArray pathsToRetain) { if (pathsToRetain == null || pathsToRetain.isEmpty()) { this.pathsToRetain = Collections.emptyList(); - } - else - { + } else { this.pathsToRetain = new LinkedList(); for (Object s : pathsToRetain) { this.pathsToRetain.add((String) s); @@ -52,25 +48,21 @@ public PathsRetainer(JSONArray pathsToRetain) } } - public PathsRetainer(List pathsToRetain) - { - this.pathsToRetain = pathsToRetain == null || pathsToRetain.size() == 0 ? - Collections.emptyList() : pathsToRetain; + public PathsRetainer(List pathsToRetain) { + this.pathsToRetain = pathsToRetain == null || pathsToRetain.size() == 0 ? Collections. emptyList() : pathsToRetain; } - public PathsRetainer(String... pathsToRetain) - { - this.pathsToRetain = pathsToRetain == null || pathsToRetain.length == 0 ? - Collections.emptyList() : new LinkedList(Arrays.asList(pathsToRetain)); + public PathsRetainer(String... pathsToRetain) { + this.pathsToRetain = pathsToRetain == null || pathsToRetain.length == 0 ? Collections. emptyList() + : new LinkedList(Arrays.asList(pathsToRetain)); } public PathsRetainer with(PathDelimiter pathDelimiter) { this.pathDelimiter = pathDelimiter; return this; } - - public JSONObject retain(JSONObject object) - { + + public JSONObject retain(JSONObject object) { /** * a path to retain which contains a path in the object, but is not itself a path in the object, * will cause the sub-path to be retained although it shouldn't: diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java index 52d5df7e..26e32a3b 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java @@ -28,17 +28,14 @@ * @since 15 March 2016. * */ -public class CopyPathsAction implements JSONNavigateAction -{ +public class CopyPathsAction implements JSONNavigateAction { protected JSONObject destTree; protected JSONObject destBranch; protected Stack destNodeStack; @Override - public boolean start(JSONObject source, Collection pathsToCopy) - { - if (source == null) - { + public boolean start(JSONObject source, Collection pathsToCopy) { + if (source == null) { destTree = null; return false; } @@ -50,30 +47,26 @@ public boolean start(JSONObject source, Collection pathsToCopy) } @Override - public boolean recurInto(TreePath jp, JSONObject o) - { + public boolean recurInto(TreePath jp, JSONObject o) { //reached JSONObject node - instantiate it and recur handleNewNode(jp, new JSONObject()); return true; } - private void handleNewNode(TreePath jp, Object node) - { + private void handleNewNode(TreePath jp, Object node) { if (!jp.hasPrev()) { return; } if (destNodeStack.peek() instanceof JSONObject) { ((JSONObject) destNodeStack.peek()).put(jp.curr(), node); - } - else if (destNodeStack.peek() instanceof JSONArray) { + } else if (destNodeStack.peek() instanceof JSONArray) { ((JSONArray) destNodeStack.peek()).add(node); } destNodeStack.push(node); } @Override - public boolean recurInto(TreePath jp, JSONArray o) - { + public boolean recurInto(TreePath jp, JSONArray o) { //reached JSONArray node - instantiate it and recur handleNewNode(jp, new JSONArray()); return true; @@ -110,8 +103,7 @@ public void recurEnd(TreePath jp, JSONArray ja) { } @Override - public boolean pathStart(String path) - { + public boolean pathStart(String path) { destBranch = new JSONObject(); destNodeStack = new Stack(); destNodeStack.push(destBranch); diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java index 8c1adb8a..c274e590 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java @@ -11,7 +11,6 @@ * @author adoneitan@gmail.com * @since 15 June 2016. */ -public interface JSONNavigateAction extends NavigateAction -{ +public interface JSONNavigateAction extends NavigateAction { } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java index 3a366c21..e2f60a24 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java @@ -9,16 +9,13 @@ * @author adoneitan@gmail.com * @since 15 June 2016. */ -public class JSONNavigator extends TreeNavigator -{ +public class JSONNavigator extends TreeNavigator { - public JSONNavigator(JSONNavigateAction action, List pathsToNavigate) - { + public JSONNavigator(JSONNavigateAction action, List pathsToNavigate) { super(action, pathsToNavigate); } - public JSONNavigator(JSONNavigateAction action, String... pathsToNavigate) - { + public JSONNavigator(JSONNavigateAction action, String... pathsToNavigate) { super(action, pathsToNavigate); } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java index 51195e1a..3493cec1 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java @@ -14,8 +14,7 @@ * @author adoneitan@gmail.com * @since 15 June 2016 */ -public interface NavigateAction, L extends List> -{ +public interface NavigateAction, L extends List> { /** * called before navigation of a new path starts * @return true if the specified path should be navigated @@ -66,7 +65,7 @@ public interface NavigateAction, L extends List, L extends List> -{ +public class TreeNavigator, L extends List> { protected List pathsToNavigate; protected NavigateAction action; protected String pathPrefix = ""; - public TreeNavigator(NavigateAction action, List pathsToNavigate) - { + public TreeNavigator(NavigateAction action, List pathsToNavigate) { if (action == null) { throw new IllegalArgumentException("NavigateAction cannot be null"); } @@ -48,32 +46,23 @@ public TreeNavigator with(String pathPrefix) { return this; } - public TreeNavigator(NavigateAction action, String... pathsToNavigate) - { + public TreeNavigator(NavigateAction action, String... pathsToNavigate) { this(action, Arrays.asList(pathsToNavigate)); } - public void nav(M object) throws Exception - { - if (action.start(object, pathsToNavigate)) - { - for (String path: pathsToNavigate) - { - try - { - if (path != null && !path.equals("") && action.pathStart(path)) - { + public void nav(M object) throws Exception { + if (action.start(object, pathsToNavigate)) { + for (String path : pathsToNavigate) { + try { + if (path != null && !path.equals("") && action.pathStart(path)) { TreePath jp = new TreePath(path, new DotDelimiter().withAcceptDelimiterInNodeName(true)); nav(jp, object); action.pathEnd(path); } - } - catch (Exception e) - { - if (action.failSilently(path ,e)) { + } catch (Exception e) { + if (action.failSilently(path, e)) { break; - } - else if (action.failFast(path, e)) { + } else if (action.failFast(path, e)) { throw e; } } @@ -82,75 +71,53 @@ else if (action.failFast(path, e)) { action.end(); } - public void nav(TreePath jp, M map) - { - if (map == null || !action.recurInto(jp, map)) - { + public void nav(TreePath jp, M map) { + if (map == null || !action.recurInto(jp, map)) { //source is null - navigation impossible return; } - if (jp.hasNext()) - { + if (jp.hasNext()) { String key = jp.next(); - if (!map.containsKey(key)) - { + if (!map.containsKey(key)) { // cannot find next element of path in the source - // the specified path does not exist in the source action.pathTailNotFound(jp, map); - } - else if (map.get(key) instanceof Map) - { + } else if (map.get(key) instanceof Map) { //reached Map type node - handle it and recur into it nav(jp, (M) map.get(key)); - } - else if (map.get(key) instanceof List) - { + } else if (map.get(key) instanceof List) { //reached List type node - handle it and recur into it nav(jp, (L) map.get(key)); - } - else if (jp.hasNext()) - { + } else if (jp.hasNext()) { // reached leaf node (not a container) in source but specified path expects children - // the specified path is illegal because it does not exist in the source. action.foundLeafBeforePathEnd(jp, map.get(key)); - } - else if (!jp.hasNext()) - { + } else if (!jp.hasNext()) { //reached leaf in source and specified path is also at leaf -> handle it action.handleLeaf(jp, map.get(key)); - } - else - { + } else { throw new IllegalStateException("fatal: unreachable code reached at '" + jp.origin() + "'"); } } action.recurEnd(jp, (M) map); } - public void nav(TreePath jp, L list) - { - if (list == null || !action.recurInto(jp, (L) list)) - { + public void nav(TreePath jp, L list) { + if (list == null || !action.recurInto(jp, (L) list)) { //list is null - navigation impossible return; } int arrIndex = 0; - for (Object arrItem : list.toArray()) - { - if (arrItem instanceof Map) - { + for (Object arrItem : list.toArray()) { + if (arrItem instanceof Map) { // clone the path so that for each object in the array, // the iterator continues from the same position in the path TreePath jpClone = getClone(jp); nav(jpClone, (M) arrItem); - } - else if (arrItem instanceof List) - { + } else if (arrItem instanceof List) { nav(jp, (L) arrItem); - } - else if (!jp.hasNext()) - { + } else if (!jp.hasNext()) { //reached leaf - handle it action.handleLeaf(jp, arrIndex, arrItem); } @@ -159,13 +126,10 @@ else if (!jp.hasNext()) action.recurEnd(jp, (L) list); } - private TreePath getClone(TreePath jp) - { - try - { + private TreePath getClone(TreePath jp) { + try { return jp.clone(); - } - catch (CloneNotSupportedException e) { + } catch (CloneNotSupportedException e) { throw new RuntimeException("failed to clone path", e); } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java index 2ea2bc07..e20a1f2b 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java @@ -7,17 +7,14 @@ * @author adoneitan@gmail.com * @since 31 May2016 */ -public class DotDelimiter extends PathDelimiter -{ +public class DotDelimiter extends PathDelimiter { protected static final char DELIM_CHAR = '.'; - public DotDelimiter() - { + public DotDelimiter() { super(DELIM_CHAR); } - public String regex() - { + public String regex() { return "\\."; } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java index 2a9fae7d..178f3a2d 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java @@ -6,14 +6,12 @@ * @author adoneitan@gmail.com * @since 31 May 2016 */ -public abstract class PathDelimiter -{ +public abstract class PathDelimiter { protected char delimChar; protected String delimStr; protected boolean acceptDelimInKey; - public PathDelimiter(char delim) - { + public PathDelimiter(char delim) { this.delimChar = delim; this.delimStr = "" + delim; } @@ -23,8 +21,7 @@ public PathDelimiter withAcceptDelimiterInNodeName(boolean acceptDelimInKey) { return this; } - public boolean accept(String key) - { + public boolean accept(String key) { if (!acceptDelimInKey && key.contains(delimStr)) return false; return true; diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java index 1c005f2f..7a341a90 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java @@ -7,18 +7,15 @@ * @author adoneitan@gmail.com * @since 31 May 2016 */ -public class SlashDelimiter extends PathDelimiter -{ +public class SlashDelimiter extends PathDelimiter { protected static final char DELIM_CHAR = '/'; - public SlashDelimiter() - { + public SlashDelimiter() { super(DELIM_CHAR); super.withAcceptDelimiterInNodeName(false); } - public String regex() - { + public String regex() { return "\\/"; } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java b/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java index a2d4f0bd..64d996e1 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java @@ -1,6 +1,5 @@ package net.minidev.json.actions.path; - import java.util.Arrays; import java.util.Map; import java.util.List; @@ -15,10 +14,12 @@ * * @author adoneitan@gmail.com */ -public class TreePath -{ +public class TreePath { + + protected enum Step { + NONE, NEXT, PREV + } - protected enum Step {NONE, NEXT, PREV} protected final String path; protected List keys; protected ListIterator keysItr; @@ -28,8 +29,7 @@ protected enum Step {NONE, NEXT, PREV} protected StringBuilder remainder; protected PathDelimiter delim; - public TreePath(String path, PathDelimiter delim) - { + public TreePath(String path, PathDelimiter delim) { this.delim = delim; checkPath(path); this.path = path; @@ -37,8 +37,7 @@ public TreePath(String path, PathDelimiter delim) reset(); } - public void reset() - { + public void reset() { keysItr = keys.listIterator(); currKey = ""; lastStep = Step.NONE; @@ -54,8 +53,7 @@ public int nextIndex() { return keysItr.nextIndex(); } - public String next() - { + public String next() { currKey = keysItr.next(); /** when changing direction the {@link ListIterator} does not really * move backward so an extra step is performed */ @@ -75,8 +73,7 @@ public int prevIndex() { return keysItr.previousIndex(); } - public String prev() - { + public String prev() { String temp = currKey; currKey = keysItr.previous(); /** when changing direction the {@link ListIterator} does not really @@ -89,8 +86,7 @@ public String prev() return currKey; } - private void remainderDecrement() - { + private void remainderDecrement() { if (length() == 1) remainder = new StringBuilder(""); else if (remainder.indexOf(delim.str()) < 0) @@ -99,8 +95,7 @@ else if (remainder.indexOf(delim.str()) < 0) remainder.delete(0, remainder.indexOf(delim.str()) + 1); } - private void originDecrement() - { + private void originDecrement() { if (length() == 1) origin = new StringBuilder(""); else if (origin.indexOf(delim.str()) < 0) @@ -109,16 +104,14 @@ else if (origin.indexOf(delim.str()) < 0) origin.delete(origin.lastIndexOf(delim.str()), origin.length()); } - private void originIncrement() - { + private void originIncrement() { if (origin.length() != 0) { origin.append(delim.chr()); } origin.append(currKey); } - private void remainderIncrement(String prev) - { + private void remainderIncrement(String prev) { if (remainder.length() == 0) remainder = new StringBuilder(prev); else @@ -171,14 +164,12 @@ public int length() { return keys.size(); } - public String subPath(int firstIndex, int lastIndex) - { + public String subPath(int firstIndex, int lastIndex) { if (lastIndex < firstIndex) { throw new IllegalArgumentException("bad call to subPath"); } StringBuilder sb = new StringBuilder(path.length()); - for (int i = firstIndex; i <= lastIndex; i++) - { + for (int i = firstIndex; i <= lastIndex; i++) { sb.append(keys.get(i)); if (i < lastIndex) { sb.append(delim.chr()); @@ -188,8 +179,7 @@ public String subPath(int firstIndex, int lastIndex) return sb.toString(); } - private void checkPath(String path) - { + private void checkPath(String path) { if (path == null || path.equals("")) throw new IllegalArgumentException("path cannot be null or empty"); if (path.startsWith(delim.str()) || path.endsWith(delim.str()) || path.contains(delim.str() + delim.str())) @@ -197,8 +187,7 @@ private void checkPath(String path) } @Override - public TreePath clone() throws CloneNotSupportedException - { + public TreePath clone() throws CloneNotSupportedException { TreePath cloned = new TreePath(this.path, this.delim); while (cloned.nextIndex() != this.nextIndex()) { cloned.next(); @@ -215,19 +204,16 @@ public TreePath clone() throws CloneNotSupportedException @Override public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; TreePath treePath = (TreePath) o; - return path().equals(treePath.path()) && - hasNext() == treePath.hasNext() && - hasPrev() == treePath.hasPrev() && - curr().equals(treePath.curr()) && - origin().equals(treePath.origin()) && - remainder().equals(treePath.remainder()) && - lastStep == treePath.lastStep && - delim.equals(treePath.delim); + return path().equals(treePath.path()) && hasNext() == treePath.hasNext() && hasPrev() == treePath.hasPrev() && curr().equals(treePath.curr()) + && origin().equals(treePath.origin()) && remainder().equals(treePath.remainder()) && lastStep == treePath.lastStep + && delim.equals(treePath.delim); } @@ -244,5 +230,3 @@ public int hashCode() { return result; } } - - diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java index 19aa6f20..11c6151b 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java @@ -10,6 +10,5 @@ * * @author adoneitan@gmail.com */ -public interface JSONTraverseAction extends TreeTraverseAction -{ +public interface JSONTraverseAction extends TreeTraverseAction { } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java index eb55c092..f2cc7594 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java @@ -19,10 +19,8 @@ * @author adoneitan@gmail.com * */ -public class JSONTraverser extends TreeTraverser -{ - public JSONTraverser(JSONTraverseAction action) - { +public class JSONTraverser extends TreeTraverser { + public JSONTraverser(JSONTraverseAction action) { super(action, new DotDelimiter()); } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java index 55b4c47a..ad0e10ea 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java @@ -9,17 +9,14 @@ * @author adoneitan@gmail.com * @since 5/24/16. */ -public class KeysPrintAction implements JSONTraverseAction -{ +public class KeysPrintAction implements JSONTraverseAction { @Override - public boolean start(JSONObject object) - { + public boolean start(JSONObject object) { return true; } @Override - public boolean traverseEntry(String fullPathToEntry, Entry entry) - { + public boolean traverseEntry(String fullPathToEntry, Entry entry) { System.out.println(entry.getKey()); return true; } @@ -35,32 +32,27 @@ public boolean recurInto(String pathToEntry, JSONArray entryValue) { } @Override - public void handleLeaf(String pathToEntry, Entry entry) - { + public void handleLeaf(String pathToEntry, Entry entry) { } @Override - public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) - { + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) { } @Override - public boolean removeEntry(String fullPathToEntry, Entry entry) - { + public boolean removeEntry(String fullPathToEntry, Entry entry) { return false; } @Override - public void end() - { + public void end() { } @Override - public Object result() - { + public Object result() { return null; } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java index f798c03e..2c8b704d 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java @@ -21,33 +21,29 @@ * @author adoneitan@gmail.com * */ -public class LocatePathsJsonAction implements JSONTraverseAction -{ +public class LocatePathsJsonAction implements JSONTraverseAction { protected List pathsFound; protected List pathsToFind; protected PathDelimiter delim; /** * - * @param pathsToFind A path to a field in the {@link JSONObject} should be specified in n-gram format where keys are chained: - * k0[[[.k1].k2]...] + * @param pathsToFind + * A path to a field in the {@link JSONObject} should be specified in n-gram format where keys are chained: k0[[[.k1].k2]...] */ - public LocatePathsJsonAction(List pathsToFind, PathDelimiter delim) - { + public LocatePathsJsonAction(List pathsToFind, PathDelimiter delim) { this.pathsToFind = pathsToFind; this.delim = delim; pathsFound = new LinkedList(); } @Override - public boolean start(JSONObject object) - { + public boolean start(JSONObject object) { return object != null && pathsToFind != null && pathsToFind.size() > 0; } @Override - public boolean traverseEntry(String fullPathToEntry, Entry entry) - { + public boolean traverseEntry(String fullPathToEntry, Entry entry) { if (!delim.accept(entry.getKey())) { return false; } @@ -76,14 +72,13 @@ public void handleLeaf(String fullPathToContainingList, int listIndex, Object li } @Override - public boolean removeEntry(String fullPathToEntry, Entry entry) - { + public boolean removeEntry(String fullPathToEntry, Entry entry) { return false; } @Override public void end() { - //nothing to do + // nothing to do } @Override @@ -91,11 +86,9 @@ public Object result() { return pathsFound; } - private void locatePath(String pathToEntry) - { - if (pathsToFind.contains(pathToEntry)) - { - //reached end of path that is being searched + private void locatePath(String pathToEntry) { + if (pathsToFind.contains(pathToEntry)) { + // reached end of path that is being searched pathsFound.add(pathToEntry); } } diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java index f8a4d7d4..9965d720 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java @@ -19,40 +19,34 @@ * @author adoneitan@gmail.com * */ -public class RemoveElementsJsonAction implements JSONTraverseAction -{ +public class RemoveElementsJsonAction implements JSONTraverseAction { protected JSONObject result; protected final Map elementsToRemove; protected final boolean allowDotChar; - public RemoveElementsJsonAction(Map elementsToRemove, boolean allowDotChar) - { + public RemoveElementsJsonAction(Map elementsToRemove, boolean allowDotChar) { this.elementsToRemove = elementsToRemove; this.allowDotChar = allowDotChar; } - public RemoveElementsJsonAction(Map elementsToRemove) - { + public RemoveElementsJsonAction(Map elementsToRemove) { this(elementsToRemove, false); } @Override - public boolean start(JSONObject object) - { + public boolean start(JSONObject object) { result = object; return object != null && elementsToRemove != null && elementsToRemove.size() > 0; } @Override - public boolean removeEntry(String fullPathToEntry, Entry entry) - { + public boolean removeEntry(String fullPathToEntry, Entry entry) { return elementsToRemove.entrySet().contains(entry); } @Override - public boolean traverseEntry(String fullPathToEntry, Entry entry) - { - //must traverse the whole object + public boolean traverseEntry(String fullPathToEntry, Entry entry) { + // must traverse the whole object return true; } @@ -67,20 +61,17 @@ public boolean recurInto(String pathToEntry, JSONArray entryValue) { } @Override - public void handleLeaf(String pathToEntry, Entry entry) - { - + public void handleLeaf(String pathToEntry, Entry entry) { } @Override - public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) - { + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) { } @Override public void end() { - //nothing to do + // nothing to do } @Override diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java index fac23fd5..e5983afd 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java @@ -19,33 +19,28 @@ * @author adoneitan@gmail.com * */ -public class RemovePathsJsonAction implements JSONTraverseAction -{ +public class RemovePathsJsonAction implements JSONTraverseAction { protected JSONObject result; protected List pathsToRemove; - public RemovePathsJsonAction(List pathsToRemove) - { + public RemovePathsJsonAction(List pathsToRemove) { this.pathsToRemove = pathsToRemove; } @Override - public boolean start(JSONObject object) - { + public boolean start(JSONObject object) { result = object; return object != null && pathsToRemove != null && pathsToRemove.size() > 0; } @Override - public boolean removeEntry(String fullPathToEntry, Entry entry) - { + public boolean removeEntry(String fullPathToEntry, Entry entry) { return pathsToRemove.contains(fullPathToEntry); } @Override - public boolean traverseEntry(String fullPathToEntry, Entry entry) - { - //must traverse the whole object + public boolean traverseEntry(String fullPathToEntry, Entry entry) { + // must traverse the whole object return true; } @@ -60,20 +55,18 @@ public boolean recurInto(String pathToEntry, JSONArray entryValue) { } @Override - public void handleLeaf(String pathToEntry, Entry entry) - { + public void handleLeaf(String pathToEntry, Entry entry) { } @Override - public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) - { + public void handleLeaf(String fullPathToContainingList, int listIndex, Object listItem) { } @Override public void end() { - //nothing to do + // nothing to do } @Override diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java index 61922c8d..eaa52528 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java @@ -13,8 +13,7 @@ * * @author adoneitan@gmail.com */ -public interface TreeTraverseAction, L extends List> -{ +public interface TreeTraverseAction, L extends List> { /** * called before any traversal of the {@link M} tree starts * @return true if traversal should start at all diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java index 39fbbfcf..ff3cea3c 100755 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java @@ -18,14 +18,12 @@ * @author adoneitan@gmail.com * */ -public class TreeTraverser, L extends List> -{ +public class TreeTraverser, L extends List> { protected TreeTraverseAction action; protected PathDelimiter delim; protected String pathPrefix = ""; - public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) - { + public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) { this.action = action; this.delim = delim; } @@ -35,67 +33,50 @@ public TreeTraverser with(String pathPrefix) { return this; } - public void traverse(M map) - { - if (action.start(map)){ + public void traverse(M map) { + if (action.start(map)) { depthFirst(pathPrefix, map); } action.end(); } - private void depthFirst(String fullPath, M map) - { + private void depthFirst(String fullPath, M map) { if (map == null || map.entrySet() == null || !action.recurInto(fullPath, map)) { return; } Iterator> it = map.entrySet().iterator(); - while (it.hasNext()) - { + while (it.hasNext()) { Entry entry = it.next(); String fullPathToEntry = buildPath(fullPath, entry.getKey()); if (!action.traverseEntry(fullPathToEntry, entry)) { continue; - } - else if (action.removeEntry(fullPathToEntry, entry)) - { + } else if (action.removeEntry(fullPathToEntry, entry)) { it.remove(); continue; } - if (entry.getValue() instanceof Map) - { + if (entry.getValue() instanceof Map) { depthFirst(fullPathToEntry, (M) entry.getValue()); - } - else if (entry.getValue() instanceof List) - { + } else if (entry.getValue() instanceof List) { depthFirst(fullPathToEntry, (L) entry.getValue()); - } - else - { + } else { action.handleLeaf(fullPathToEntry, entry); } } } - private void depthFirst(String fullPath, L list) - { + private void depthFirst(String fullPath, L list) { if (!action.recurInto(fullPath, (L) list)) { return; } int listIndex = 0; - for (Object listItem : list.toArray()) - { - if (listItem instanceof Map) - { + for (Object listItem : list.toArray()) { + if (listItem instanceof Map) { depthFirst(fullPath, (M) listItem); - } - else if (listItem instanceof List) - { + } else if (listItem instanceof List) { depthFirst(fullPath, (L) listItem); - } - else - { + } else { action.handleLeaf(fullPath, listIndex, listItem); } listIndex++; diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java index 5fba45b8..d6c549b7 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java +++ b/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java @@ -25,7 +25,6 @@ * Object result = tAction.result(); * * - * @author adoneitan@gmail.com */ package net.minidev.json.actions.traverse; \ No newline at end of file diff --git a/json-smart/src/main/java/net/minidev/json/annotate/JsonIgnore.java b/json-smart/src/main/java/net/minidev/json/annotate/JsonIgnore.java index a45e4465..77ad017f 100644 --- a/json-smart/src/main/java/net/minidev/json/annotate/JsonIgnore.java +++ b/json-smart/src/main/java/net/minidev/json/annotate/JsonIgnore.java @@ -20,8 +20,6 @@ * Read/Write using field if the field is public (default ) * * - * - * * @author uriel * */ From 83e8aea947b3b8364dc955885f0c5f0faba20d86 Mon Sep 17 00:00:00 2001 From: UrielCh Date: Fri, 23 Sep 2016 19:24:55 -0700 Subject: [PATCH 12/18] remove executable flad on java files --- .../src/main/java/net/minidev/json/actions/ElementRemover.java | 0 .../src/main/java/net/minidev/json/actions/PathLocator.java | 0 .../src/main/java/net/minidev/json/actions/PathRemover.java | 0 .../src/main/java/net/minidev/json/actions/PathReplicator.java | 0 .../src/main/java/net/minidev/json/actions/PathsRetainer.java | 0 .../java/net/minidev/json/actions/navigate/CopyPathsAction.java | 0 .../net/minidev/json/actions/navigate/JSONNavigateAction.java | 0 .../java/net/minidev/json/actions/navigate/NavigateAction.java | 0 .../java/net/minidev/json/actions/navigate/TreeNavigator.java | 0 .../src/main/java/net/minidev/json/actions/path/TreePath.java | 0 .../net/minidev/json/actions/traverse/JSONTraverseAction.java | 0 .../java/net/minidev/json/actions/traverse/JSONTraverser.java | 0 .../net/minidev/json/actions/traverse/LocatePathsJSONAction.java | 0 .../minidev/json/actions/traverse/RemoveElementsJSONAction.java | 0 .../net/minidev/json/actions/traverse/RemovePathsJsonAction.java | 0 .../net/minidev/json/actions/traverse/RetainPathsJsonAction.java | 0 .../net/minidev/json/actions/traverse/TreeTraverseAction.java | 0 .../java/net/minidev/json/actions/traverse/TreeTraverser.java | 0 .../java/net/minidev/json/test/actions/ElementRemoverTest.java | 0 .../test/java/net/minidev/json/test/actions/PathLocatorTest.java | 0 .../test/java/net/minidev/json/test/actions/PathRemoverTest.java | 0 .../java/net/minidev/json/test/actions/PathReplicatorTest.java | 0 .../java/net/minidev/json/test/actions/PathsRetainerTest.java | 0 .../src/test/java/net/minidev/json/test/actions/TreePathTest.java | 0 24 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/PathLocator.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/PathRemover.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java mode change 100755 => 100644 json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java mode change 100755 => 100644 json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java mode change 100755 => 100644 json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java mode change 100755 => 100644 json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java mode change 100755 => 100644 json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java mode change 100755 => 100644 json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java mode change 100755 => 100644 json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java b/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java b/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java b/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java b/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java old mode 100755 new mode 100644 diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java old mode 100755 new mode 100644 diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java old mode 100755 new mode 100644 diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java old mode 100755 new mode 100644 diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java old mode 100755 new mode 100644 diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java old mode 100755 new mode 100644 diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java old mode 100755 new mode 100644 diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java old mode 100755 new mode 100644 From 7447287c1c8242059ca8cbde3073bdf3f5e5579c Mon Sep 17 00:00:00 2001 From: UrielCh Date: Fri, 23 Sep 2016 19:38:05 -0700 Subject: [PATCH 13/18] reformat --- .../net/minidev/json/actions/PathLocator.java | 25 ++-- .../java/net/minidev/json/test/TestNavi.java | 4 +- .../json/test/actions/ElementRemoverTest.java | 10 +- .../json/test/actions/PathLocatorTest.java | 38 ++---- .../json/test/actions/PathRemoverTest.java | 39 ++---- .../json/test/actions/PathReplicatorTest.java | 113 ++++++------------ .../json/test/actions/PathsRetainerTest.java | 65 ++++------ .../json/test/actions/TreePathTest.java | 14 +-- .../json/test/strict/TestExcessiveComma.java | 3 +- .../json/test/strict/TestTaillingJunk.java | 10 +- .../json/test/strict/TestZeroLead.java | 20 ++-- .../testMapping/TestCustomMappingInstant.java | 3 +- 12 files changed, 113 insertions(+), 231 deletions(-) diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java index e75d5736..ada5d9d5 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java +++ b/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java @@ -28,18 +28,14 @@ * * @author adoneitan@gmail.com */ -public class PathLocator -{ +public class PathLocator { protected List pathsToFind; protected PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); - public PathLocator(JSONArray pathsToFind) - { + public PathLocator(JSONArray pathsToFind) { if (pathsToFind == null || pathsToFind.isEmpty()) { this.pathsToFind = Collections.emptyList(); - } - else - { + } else { this.pathsToFind = new ArrayList(); for (Object s : pathsToFind) { this.pathsToFind.add((String) s); @@ -47,16 +43,12 @@ public PathLocator(JSONArray pathsToFind) } } - public PathLocator(List pathsToFind) - { - this.pathsToFind = pathsToFind == null || pathsToFind.size() == 0 ? - Collections.emptyList() : pathsToFind; + public PathLocator(List pathsToFind) { + this.pathsToFind = pathsToFind == null || pathsToFind.size() == 0 ? Collections. emptyList() : pathsToFind; } - public PathLocator(String... pathsToFind) - { - this.pathsToFind = pathsToFind == null || pathsToFind.length == 0 ? - Collections.emptyList() : Arrays.asList(pathsToFind); + public PathLocator(String... pathsToFind) { + this.pathsToFind = pathsToFind == null || pathsToFind.length == 0 ? Collections. emptyList() : Arrays.asList(pathsToFind); } public PathLocator with(PathDelimiter pathDelimiter) { @@ -64,8 +56,7 @@ public PathLocator with(PathDelimiter pathDelimiter) { return this; } - public List locate(JSONObject object) - { + public List locate(JSONObject object) { JSONTraverseAction action = new LocatePathsJsonAction(this.pathsToFind, pathDelimiter); JSONTraverser traversal = new JSONTraverser(action).with(pathDelimiter); traversal.traverse(object); diff --git a/json-smart/src/test/java/net/minidev/json/test/TestNavi.java b/json-smart/src/test/java/net/minidev/json/test/TestNavi.java index 64607302..f4d22f82 100644 --- a/json-smart/src/test/java/net/minidev/json/test/TestNavi.java +++ b/json-smart/src/test/java/net/minidev/json/test/TestNavi.java @@ -44,11 +44,11 @@ public void testNaviWriteArray() { JSONNavi nav = JSONNavi.newInstance(); nav.set("type", "bundle").at("data").array().at(0).set("type", "object").set("name", "obj1").up().at(1).set("type", "object").set("name", "obj2").root(); String s2 = nav.toString(); - assertEquals(expected, nav.toString()); + assertEquals(expected, s2); nav = JSONNavi.newInstance(); nav.set("type", "bundle").at("data").array().atNext().set("type", "object").set("name", "obj1").up().atNext().set("type", "object").set("name", "obj2").root(); s2 = nav.toString(); - assertEquals(expected, nav.toString()); + assertEquals(expected, s2); } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java index 327fa2d1..52f1f134 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java @@ -1,6 +1,5 @@ package net.minidev.json.test.actions; -import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; import net.minidev.json.JSONValue; import net.minidev.json.actions.ElementRemover; @@ -19,8 +18,7 @@ * @author adoneitan@gmail.com */ @RunWith(Parameterized.class) -public class ElementRemoverTest -{ +public class ElementRemoverTest { private String jsonToClean; private String elementsToRemove; private String expectedJson; @@ -33,10 +31,8 @@ public ElementRemoverTest(String jsonToClean, String elementsToRemove, String ex } @Parameterized.Parameters - public static Collection params() - { - return Arrays.asList(new Object[][]{ - + public static Collection params() { + return Arrays.asList(new String[][]{ {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", null, "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{}", "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k0\":\"v2\"}", "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java index 29734110..881fd0e6 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java @@ -34,8 +34,7 @@ public PathLocatorTest(String jsonToSearch, Object keysToFind, String[] expected } @Parameterized.Parameters - public static Collection params() - { + public static Collection params() { return Arrays.asList(new Object[][]{ //nulls, bad/empty keys @@ -115,44 +114,27 @@ public void test() throws ParseException private PathLocator switchKeyToRemove() { long m = System.currentTimeMillis(); - if (keysToFind == null && m % 4 == 0) - { + if (keysToFind == null && m % 4 == 0) { System.out.println("cast to String"); return new PathLocator((String)null); - } - else if (keysToFind == null && m % 4 == 1) - { + } else if (keysToFind == null && m % 4 == 1) { System.out.println("cast to String[]"); return new PathLocator((String[])null); - } - else if (keysToFind == null && m % 4 == 2) - { + } else if (keysToFind == null && m % 4 == 2) { System.out.println("cast to JSONArray"); return new PathLocator((JSONArray)null); - } - else if (keysToFind == null && m % 4 == 3) - { + } else if (keysToFind == null && m % 4 == 3) { System.out.println("cast to List"); return new PathLocator((List)null); - } - else if (keysToFind instanceof String) - { + } else if (keysToFind instanceof String) { return new PathLocator((String) keysToFind); - } - else if (keysToFind instanceof String[]) - { + } else if (keysToFind instanceof String[]) { return new PathLocator((String[]) keysToFind); - } - else if (keysToFind instanceof JSONArray) - { + } else if (keysToFind instanceof JSONArray) { return new PathLocator((JSONArray) keysToFind); - } - else if (keysToFind instanceof List) - { + } else if (keysToFind instanceof List) { return new PathLocator((List) keysToFind); - } - else - { + } else { throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java index 2f18cfc7..9196757a 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java @@ -36,10 +36,8 @@ public PathRemoverTest(String jsonToClean, Object keyToRemove, String expectedJs } @Parameterized.Parameters - public static Collection params() - { + public static Collection params() { return Arrays.asList(new Object[][]{ - {null, "key", null }, // null json {"{}", "key", "{}" }, // empty json {"{\"first\": null}", null, "{\"first\": null}" }, // null key @@ -91,44 +89,27 @@ public void test() throws ParseException private PathRemover switchKeyToRemove() { long m = System.currentTimeMillis(); - if (keyToRemove == null && m % 4 == 0) - { + if (keyToRemove == null && m % 4 == 0) { System.out.println("cast to String"); return new PathRemover((String)null); - } - else if (keyToRemove == null && m % 4 == 1) - { + } else if (keyToRemove == null && m % 4 == 1) { System.out.println("cast to String[]"); return new PathRemover((String[])null); - } - else if (keyToRemove == null && m % 4 == 2) - { + } else if (keyToRemove == null && m % 4 == 2) { System.out.println("cast to JSONArray"); return new PathRemover((JSONArray)null); - } - else if (keyToRemove == null && m % 4 == 3) - { + } else if (keyToRemove == null && m % 4 == 3) { System.out.println("cast to List"); return new PathRemover((List)null); - } - else if (keyToRemove instanceof String) - { + } else if (keyToRemove instanceof String) { return new PathRemover((String)keyToRemove); - } - else if (keyToRemove instanceof String[]) - { + } else if (keyToRemove instanceof String[]) { return new PathRemover((String[])keyToRemove); - } - else if (keyToRemove instanceof JSONArray) - { + } else if (keyToRemove instanceof JSONArray) { return new PathRemover((JSONArray)keyToRemove); - } - else if (keyToRemove instanceof List) - { + } else if (keyToRemove instanceof List) { return new PathRemover((List)keyToRemove); - } - else - { + } else { throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java index 3c9c13de..2feecd50 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java @@ -19,23 +19,20 @@ * @author adoneitan@gmail.com */ @RunWith(Parameterized.class) -public class PathReplicatorTest -{ +public class PathReplicatorTest { private String jsonSource; private Object pathsToCopy; private Object expected; - public PathReplicatorTest(String jsonSource, Object pathsToCopy, Object expected) - { + public PathReplicatorTest(String jsonSource, Object pathsToCopy, Object expected) { this.jsonSource = jsonSource; this.pathsToCopy = pathsToCopy; this.expected = expected; } @Parameterized.Parameters - public static Collection params() - { - return Arrays.asList(new Object[][]{ + public static Collection params() { + return Arrays.asList(new Object[][] { //nulls, bad/empty keys {null, null, null }, @@ -120,9 +117,8 @@ public static Collection params() } @Test - public void test() throws Exception - { - JSONObject objectSource = jsonSource != null ? (JSONObject) JSONValue.parseWithException(jsonSource) :null; + public void test() throws Exception { + JSONObject objectSource = jsonSource != null ? (JSONObject) JSONValue.parseWithException(jsonSource) : null; PathReplicator copier = switchKeyToCopy(); JSONObject copied = copier.replicate(objectSource); JSONObject expectedObj = expected != null ? (JSONObject) JSONValue.parseWithException((String) expected) : null; @@ -130,101 +126,64 @@ public void test() throws Exception } @Test - public void test2() throws Exception - { - JSONObject objectSource = jsonSource != null ? (JSONObject) JSONValue.parseWithException(jsonSource) :null; + public void test2() throws Exception { + JSONObject objectSource = jsonSource != null ? (JSONObject) JSONValue.parseWithException(jsonSource) : null; PathReplicator copier = switchKeyToCopy2(); JSONObject copied = copier.replicate(objectSource); JSONObject expectedObj = expected != null ? (JSONObject) JSONValue.parseWithException((String) expected) : null; assertEquals(expectedObj, copied); } - private PathReplicator switchKeyToCopy() - { + private PathReplicator switchKeyToCopy() { long m = System.currentTimeMillis(); - if (pathsToCopy == null && m % 4 == 0) - { + if (pathsToCopy == null && m % 4 == 0) { System.out.println("cast to String"); - return new PathReplicator((String)null); - } - else if (pathsToCopy == null && m % 4 == 1) - { + return new PathReplicator((String) null); + } else if (pathsToCopy == null && m % 4 == 1) { System.out.println("cast to String[]"); - return new PathReplicator((String[])null); - } - else if (pathsToCopy == null && m % 4 == 2) - { + return new PathReplicator((String[]) null); + } else if (pathsToCopy == null && m % 4 == 2) { System.out.println("cast to JSONArray"); - return new PathReplicator((JSONArray)null); - } - else if (pathsToCopy == null && m % 4 == 3) - { + return new PathReplicator((JSONArray) null); + } else if (pathsToCopy == null && m % 4 == 3) { System.out.println("cast to List"); - return new PathReplicator((List)null); - } - else if (pathsToCopy instanceof String) - { + return new PathReplicator((List) null); + } else if (pathsToCopy instanceof String) { return new PathReplicator((String) pathsToCopy); - } - else if (pathsToCopy instanceof String[]) - { + } else if (pathsToCopy instanceof String[]) { return new PathReplicator((String[]) pathsToCopy); - } - else if (pathsToCopy instanceof JSONArray) - { + } else if (pathsToCopy instanceof JSONArray) { return new PathReplicator((JSONArray) pathsToCopy); - } - else if (pathsToCopy instanceof List) - { + } else if (pathsToCopy instanceof List) { return new PathReplicator((List) pathsToCopy); - } - else - { + } else { throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); } } - private PathReplicator switchKeyToCopy2() - { + private PathReplicator switchKeyToCopy2() { long m = System.currentTimeMillis(); - if (pathsToCopy == null && m % 4 == 0) - { + if (pathsToCopy == null && m % 4 == 0) { System.out.println("cast to String"); - return new PathReplicator((String)null); - } - else if (pathsToCopy == null && m % 4 == 1) - { + return new PathReplicator((String) null); + } else if (pathsToCopy == null && m % 4 == 1) { System.out.println("cast to String[]"); - return new PathReplicator((String[])null); - } - else if (pathsToCopy == null && m % 4 == 2) - { + return new PathReplicator((String[]) null); + } else if (pathsToCopy == null && m % 4 == 2) { System.out.println("cast to JSONArray"); - return new PathReplicator((JSONArray)null); - } - else if (pathsToCopy == null && m % 4 == 3) - { + return new PathReplicator((JSONArray) null); + } else if (pathsToCopy == null && m % 4 == 3) { System.out.println("cast to List"); - return new PathReplicator((List)null); - } - else if (pathsToCopy instanceof String) - { + return new PathReplicator((List) null); + } else if (pathsToCopy instanceof String) { return new PathReplicator((String) pathsToCopy); - } - else if (pathsToCopy instanceof String[]) - { + } else if (pathsToCopy instanceof String[]) { return new PathReplicator((String[]) pathsToCopy); - } - else if (pathsToCopy instanceof JSONArray) - { + } else if (pathsToCopy instanceof JSONArray) { return new PathReplicator((JSONArray) pathsToCopy); - } - else if (pathsToCopy instanceof List) - { + } else if (pathsToCopy instanceof List) { return new PathReplicator((List) pathsToCopy); - } - else - { + } else { throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java index 17daf438..f079e801 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java @@ -21,23 +21,21 @@ * @author adoneitan@gmail.com */ @RunWith(Parameterized.class) -public class PathsRetainerTest -{ +public class PathsRetainerTest { private String jsonToReduce; private Object keyToKeep; private String expectedReducedJson; - public PathsRetainerTest(String jsonToReduce, Object keyToKeep, String expectedReducedJson) - { + public PathsRetainerTest(String jsonToReduce, Object keyToKeep, String expectedReducedJson) { this.jsonToReduce = jsonToReduce; this.keyToKeep = keyToKeep; this.expectedReducedJson = expectedReducedJson; } @Parameterized.Parameters - public static Collection params() - { - return Arrays.asList(new Object[][]{ + public static Collection params() { + return Arrays + .asList(new Object[][] { //nulls, bad/empty keys {null, null, null }, @@ -113,56 +111,37 @@ public static Collection params() } @Test - public void test() throws ParseException - { - JSONObject objectToReduce = jsonToReduce != null ? (JSONObject) JSONValue.parseWithException(jsonToReduce) :null; - JSONObject expectedReducedObj = expectedReducedJson != null ? (JSONObject) JSONValue.parseWithException(expectedReducedJson):null; + public void test() throws ParseException { + JSONObject objectToReduce = jsonToReduce != null ? (JSONObject) JSONValue.parseWithException(jsonToReduce) : null; + JSONObject expectedReducedObj = expectedReducedJson != null ? (JSONObject) JSONValue.parseWithException(expectedReducedJson) : null; PathsRetainer retainer = switchKeyToRemove().with(new DotDelimiter().withAcceptDelimiterInNodeName(false)); JSONObject reducedObj = retainer.retain(objectToReduce); assertEquals(expectedReducedObj, reducedObj); } - private PathsRetainer switchKeyToRemove() - { + private PathsRetainer switchKeyToRemove() { long m = System.currentTimeMillis(); - if (keyToKeep == null && m % 4 == 0) - { + if (keyToKeep == null && m % 4 == 0) { System.out.println("cast to String"); - return new PathsRetainer((String)null); - } - else if (keyToKeep == null && m % 4 == 1) - { + return new PathsRetainer((String) null); + } else if (keyToKeep == null && m % 4 == 1) { System.out.println("cast to String[]"); - return new PathsRetainer((String[])null); - } - else if (keyToKeep == null && m % 4 == 2) - { + return new PathsRetainer((String[]) null); + } else if (keyToKeep == null && m % 4 == 2) { System.out.println("cast to JSONArray"); - return new PathsRetainer((JSONArray)null); - } - else if (keyToKeep == null && m % 4 == 3) - { + return new PathsRetainer((JSONArray) null); + } else if (keyToKeep == null && m % 4 == 3) { System.out.println("cast to List"); - return new PathsRetainer((List)null); - } - else if (keyToKeep instanceof String) - { + return new PathsRetainer((List) null); + } else if (keyToKeep instanceof String) { return new PathsRetainer((String) keyToKeep); - } - else if (keyToKeep instanceof String[]) - { + } else if (keyToKeep instanceof String[]) { return new PathsRetainer((String[]) keyToKeep); - } - else if (keyToKeep instanceof JSONArray) - { + } else if (keyToKeep instanceof JSONArray) { return new PathsRetainer((JSONArray) keyToKeep); - } - else if (keyToKeep instanceof List) - { + } else if (keyToKeep instanceof List) { return new PathsRetainer((List) keyToKeep); - } - else - { + } else { throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java index 876bfb3f..4a890f39 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java @@ -11,13 +11,11 @@ /** * @author adoneitan@gmail.com */ -public class TreePathTest -{ +public class TreePathTest { private static final PathDelimiter delim = new DotDelimiter().withAcceptDelimiterInNodeName(true); @Test - public void testIterator() - { + public void testIterator() { TreePath jp = new TreePath("a.b.c", delim); assertTrue(jp.nextIndex() == 0); assertTrue(jp.prevIndex() == -1); @@ -72,15 +70,13 @@ public void testIterator() } @Test - public void testSubPath() - { + public void testSubPath() { TreePath jp = new TreePath("a.b.c", delim); - assertTrue(jp.subPath(1,2).equals("b.c")); + assertTrue(jp.subPath(1, 2).equals("b.c")); } @Test - public void testClone() throws CloneNotSupportedException - { + public void testClone() throws CloneNotSupportedException { TreePath jp1 = new TreePath("a.b.c", delim); TreePath jp2 = jp1.clone(); assertTrue(jp1.equals(jp2)); diff --git a/json-smart/src/test/java/net/minidev/json/test/strict/TestExcessiveComma.java b/json-smart/src/test/java/net/minidev/json/test/strict/TestExcessiveComma.java index c24b3a5d..6d072929 100644 --- a/json-smart/src/test/java/net/minidev/json/test/strict/TestExcessiveComma.java +++ b/json-smart/src/test/java/net/minidev/json/test/strict/TestExcessiveComma.java @@ -23,14 +23,13 @@ public void testExcessiveComma3A() throws Exception { MustThrows.testStrictInvalidJson(s, ParseException.ERROR_UNEXPECTED_CHAR); JSONValue.parseWithException(s); } - + public void testExcessiveComma4A() throws Exception { String s = "[,5]"; MustThrows.testStrictInvalidJson(s, ParseException.ERROR_UNEXPECTED_CHAR); JSONValue.parseWithException(s); } - public void testExcessiveComma1O() throws Exception { String s = "{\"a\":1,,\"b\":1}"; MustThrows.testStrictInvalidJson(s, ParseException.ERROR_UNEXPECTED_CHAR); diff --git a/json-smart/src/test/java/net/minidev/json/test/strict/TestTaillingJunk.java b/json-smart/src/test/java/net/minidev/json/test/strict/TestTaillingJunk.java index 5f25fcec..9b204acd 100644 --- a/json-smart/src/test/java/net/minidev/json/test/strict/TestTaillingJunk.java +++ b/json-smart/src/test/java/net/minidev/json/test/strict/TestTaillingJunk.java @@ -14,7 +14,7 @@ public class TestTaillingJunk extends TestCase { public void testTaillingSpace() throws Exception { String s = "{\"t\":0} "; MustThrows.testInvalidJson(s, JSONParser.MODE_STRICTEST, ParseException.ERROR_UNEXPECTED_TOKEN); - + s = "{\"t\":0} "; JSONObject o = (JSONObject) new JSONParser(JSONParser.MODE_STRICTEST | JSONParser.ACCEPT_TAILLING_SPACE).parse(s); assertEquals(o.get("t"), 0); @@ -36,9 +36,9 @@ public void testTaillingDataPermisive() throws Exception { JSONObject o = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE).parse(s); assertEquals(o.get("t"), 0); } - + public void testTaillingDataWithSpaceAllowed() throws Exception { - String s = "{\"t\":0}{"; - MustThrows.testInvalidJson(s, JSONParser.MODE_STRICTEST | JSONParser.ACCEPT_TAILLING_SPACE, ParseException.ERROR_UNEXPECTED_TOKEN); - } + String s = "{\"t\":0}{"; + MustThrows.testInvalidJson(s, JSONParser.MODE_STRICTEST | JSONParser.ACCEPT_TAILLING_SPACE, ParseException.ERROR_UNEXPECTED_TOKEN); + } } diff --git a/json-smart/src/test/java/net/minidev/json/test/strict/TestZeroLead.java b/json-smart/src/test/java/net/minidev/json/test/strict/TestZeroLead.java index e163f408..0ed53e00 100644 --- a/json-smart/src/test/java/net/minidev/json/test/strict/TestZeroLead.java +++ b/json-smart/src/test/java/net/minidev/json/test/strict/TestZeroLead.java @@ -42,7 +42,7 @@ public void test01Float() throws Exception { // PERMISIVE JSONValue.parseWithException(s); } - + public void test00001() throws Exception { String s = "{\"t\":00001}"; JSONObject o = (JSONObject) new JSONParser(JSONParser.MODE_PERMISSIVE).parse(s); @@ -57,14 +57,14 @@ public void test00001Strict() throws Exception { } // disable in 1.1 -// public void testDup() throws Exception { -// String s = "{'t':1,'t':2}"; -// try { -// new JSONParser(JSONParser.MODE_PERMISSIVE).parse(s); -// assertEquals("Should Stack", ""); -// } catch (ParseException e) { -// assertEquals(ParseException.ERROR_UNEXPECTED_DUPLICATE_KEY, e.getErrorType()); -// } -// } + // public void testDup() throws Exception { + // String s = "{'t':1,'t':2}"; + // try { + // new JSONParser(JSONParser.MODE_PERMISSIVE).parse(s); + // assertEquals("Should Stack", ""); + // } catch (ParseException e) { + // assertEquals(ParseException.ERROR_UNEXPECTED_DUPLICATE_KEY, e.getErrorType()); + // } + // } } diff --git a/json-smart/src/test/java/net/minidev/json/testMapping/TestCustomMappingInstant.java b/json-smart/src/test/java/net/minidev/json/testMapping/TestCustomMappingInstant.java index c06dcec6..49884c64 100644 --- a/json-smart/src/test/java/net/minidev/json/testMapping/TestCustomMappingInstant.java +++ b/json-smart/src/test/java/net/minidev/json/testMapping/TestCustomMappingInstant.java @@ -2,7 +2,6 @@ import java.io.IOException; -import junit.framework.Assert; import junit.framework.TestCase; import net.minidev.json.JSONStyle; import net.minidev.json.JSONValue; @@ -23,7 +22,7 @@ public void test_dummy() throws IOException { ParseException e = null; JSONValue.toJSONString(true, JSONStyle.MAX_COMPRESS); - Assert.assertEquals(true, true); + //Assert.assertEquals(true, true); } // Need JDK 1.8 From 6eb26700c89bcffdec27a398e2ac451921bdab21 Mon Sep 17 00:00:00 2001 From: UrielCh Date: Fri, 23 Sep 2016 20:11:36 -0700 Subject: [PATCH 14/18] make test unit more readable --- .../json/test/actions/ElementRemoverTest.java | 129 ++++++++-------- .../test/actions/KeysPrintActionTest.java | 50 +++--- .../json/test/actions/PathLocatorTest.java | 2 +- .../json/test/actions/PathRemoverTest.java | 2 +- .../json/test/actions/PathReplicatorTest.java | 146 +++++++++--------- 5 files changed, 170 insertions(+), 159 deletions(-) diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java index 52f1f134..5a8113bf 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java @@ -23,80 +23,85 @@ public class ElementRemoverTest { private String elementsToRemove; private String expectedJson; - public ElementRemoverTest(String jsonToClean, String elementsToRemove, String expectedJson) - { - this.jsonToClean = jsonToClean; - this.elementsToRemove = elementsToRemove; - this.expectedJson = expectedJson; + public ElementRemoverTest(String jsonToClean, String elementsToRemove, String expectedJson) { + this.jsonToClean = filter(jsonToClean); + this.elementsToRemove = filter(elementsToRemove); + this.expectedJson = filter(expectedJson); } + private static String filter(String test) { + if (test == null) + return null; + return test.replace("'", "\""); + } + @Parameterized.Parameters - public static Collection params() { - return Arrays.asList(new String[][]{ - {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", null, "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, - {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{}", "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, - {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k0\":\"v2\"}", "{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, - {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k2\":\"v2\"}", "{\"k0\":{},\"k1\":{\"k3\":\"v3\"}}"}, - {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k0\":{\"k2\":\"v2\"}}", "{\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}"}, - {"{\"k0\":{\"k2\":\"v2\"},\"k1\":{\"k2\":\"v2\",\"k3\":\"v3\"}}", "{\"k2\":\"v2\",\"k3\":\"v3\"}", "{\"k0\":{},\"k1\":{}}"}, - {"{\"k0\":{}}", "{}", "{\"k0\":{}}"}, + public static Collection params() { + List list = Arrays.asList(new String[][]{ + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", null, "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{}", "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k0':'v2'}", "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k2':'v2'}", "{'k0':{},'k1':{'k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k0':{'k2':'v2'}}", "{'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k2':'v2','k3':'v3'}", "{'k0':{},'k1':{}}"}, + {"{'k0':{}}", "{}", "{'k0':{}}"}, }); + return list; } @Test - public void test() throws ParseException - { + public void test() throws ParseException { JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; - JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson): null; - JSONObject toRemove = elementsToRemove != null ? (JSONObject) JSONValue.parseWithException(elementsToRemove): null; + JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson) : null; + JSONObject toRemove = elementsToRemove != null ? (JSONObject) JSONValue.parseWithException(elementsToRemove) : null; ElementRemover er = new ElementRemover(toRemove); er.remove(objectToClean); assertEquals(expectedObject, objectToClean); } -// private ElementRemover switchKeyToRemove() -// { -// long m = System.currentTimeMillis(); -// if (elementsToRemove == null && m % 4 == 0) -// { -// System.out.println("cast to String"); -// return new ElementRemover((String)null); -// } -// else if (elementsToRemove == null && m % 4 == 1) -// { -// System.out.println("cast to String[]"); -// return new ElementRemover((String[])null); -// } -// else if (elementsToRemove == null && m % 4 == 2) -// { -// System.out.println("cast to JSONArray"); -// return new ElementRemover((JSONArray)null); -// } -// else if (elementsToRemove == null && m % 4 == 3) -// { -// System.out.println("cast to List"); -// return new ElementRemover((List)null); -// } -// else if (elementsToRemove instanceof String) -// { -// return new ElementRemover((String) elementsToRemove); -// } -// else if (elementsToRemove instanceof String[]) -// { -// return new ElementRemover((String[]) elementsToRemove); -// } -// else if (elementsToRemove instanceof JSONArray) -// { -// return new ElementRemover((JSONArray) elementsToRemove); -// } -// else if (elementsToRemove instanceof List) -// { -// return new ElementRemover((List) elementsToRemove); -// } -// else -// { -// throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); -// } -// } + // private ElementRemover switchKeyToRemove() + // { + // long m = System.currentTimeMillis(); + // if (elementsToRemove == null && m % 4 == 0) + // { + // System.out.println("cast to String"); + // return new ElementRemover((String)null); + // } + // else if (elementsToRemove == null && m % 4 == 1) + // { + // System.out.println("cast to String[]"); + // return new ElementRemover((String[])null); + // } + // else if (elementsToRemove == null && m % 4 == 2) + // { + // System.out.println("cast to JSONArray"); + // return new ElementRemover((JSONArray)null); + // } + // else if (elementsToRemove == null && m % 4 == 3) + // { + // System.out.println("cast to List"); + // return new ElementRemover((List)null); + // } + // else if (elementsToRemove instanceof String) + // { + // return new ElementRemover((String) elementsToRemove); + // } + // else if (elementsToRemove instanceof String[]) + // { + // return new ElementRemover((String[]) elementsToRemove); + // } + // else if (elementsToRemove instanceof JSONArray) + // { + // return new ElementRemover((JSONArray) elementsToRemove); + // } + // else if (elementsToRemove instanceof List) + // { + // return new ElementRemover((List) elementsToRemove); + // } + // else + // { + // throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + // } + // } } diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java index 52dce46d..20f5512b 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java @@ -11,35 +11,33 @@ * @author adoneitan@gmail.com * @since 30 May 2016 */ -public class KeysPrintActionTest -{ +public class KeysPrintActionTest { @Test - public void test() throws ParseException - { + public void test() throws ParseException { KeysPrintAction p = new KeysPrintAction(); JSONTraverser t = new JSONTraverser(p); - JSONObject jo = (JSONObject) JSONValue.parseWithException( - "{" + - "\"k0\":{" + - "\"k01\":{" + - "\"k011\":\"v2\"" + - "}" + - "}," + - "\"k1\":{" + - "\"k11\":{" + - "\"k111\":\"v5\"" + - "}," + - "\"k12\":{" + - "\"k121\":\"v5\"" + - "}" + - "}," + - "\"k3\":{" + - "\"k31\":{" + - "\"k311\":\"v5\"" + - "}" + - "}" + - "}" - ); + + String data ="{" + + "'k0':{" + + "'k01':{" + + "'k011':'v2'" + + "}" + + "}," + + "'k1':{" + + "'k11':{" + + "'k111':'v5'" + + "}," + + "'k12':{" + + "'k121':'v5'" + + "}" + + "}," + + "'k3':{" + + "'k31':{" + + "'k311':'v5'" + + "}" + + "}" + + "}"; + JSONObject jo = (JSONObject) JSONValue.parseWithException(data.replace("'", "\"")); t.traverse(jo); } } \ No newline at end of file diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java index 881fd0e6..ba904c34 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java @@ -34,7 +34,7 @@ public PathLocatorTest(String jsonToSearch, Object keysToFind, String[] expected } @Parameterized.Parameters - public static Collection params() { + public static Collection params() { return Arrays.asList(new Object[][]{ //nulls, bad/empty keys diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java index 9196757a..73e62226 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java @@ -36,7 +36,7 @@ public PathRemoverTest(String jsonToClean, Object keyToRemove, String expectedJs } @Parameterized.Parameters - public static Collection params() { + public static Collection params() { return Arrays.asList(new Object[][]{ {null, "key", null }, // null json {"{}", "key", "{}" }, // empty json diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java index 2feecd50..8bcb8db8 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java +++ b/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java @@ -25,94 +25,102 @@ public class PathReplicatorTest { private Object expected; public PathReplicatorTest(String jsonSource, Object pathsToCopy, Object expected) { - this.jsonSource = jsonSource; - this.pathsToCopy = pathsToCopy; - this.expected = expected; + this.jsonSource = filter(jsonSource); + this.pathsToCopy = filter(pathsToCopy); + this.expected = filter(expected); } + @SuppressWarnings("unchecked") + private static T filter(T obj) { + if (obj == null) + return null; + if (obj instanceof String) + return (T)(((String)obj).replace("'", "\"")); + return obj; + } + @Parameterized.Parameters - public static Collection params() { + public static Collection params() { return Arrays.asList(new Object[][] { - //nulls, bad/empty keys - {null, null, null }, - {null, "", null }, - {null, "k1", null }, - {null, new String[]{}, null }, - {null, new JSONArray(), null }, - {null, new ArrayList(0), null },//5 + {null, null, null }, + {null, "", null }, + {null, "k1", null }, + {null, new String[]{}, null }, + {null, new JSONArray(), null }, + {null, new ArrayList(0), null },//5 //empty json, bad/empty keys - {"{}", null, "{}" }, - {"{}", "", "{}" }, - {"{}", "k1", "{}" }, - {"{}", new String[]{}, "{}" }, - {"{}", new JSONArray(), "{}" }, - {"{}", new ArrayList(0), "{}" },//11 + {"{}", null, "{}" }, + {"{}", "", "{}" }, + {"{}", "k1", "{}" }, + {"{}", new String[]{}, "{}" }, + {"{}", new JSONArray(), "{}" }, + {"{}", new ArrayList(0), "{}" },//11 //simple json, bad/empty keys - {"{\"k0\":\"v0\"}", null, "{}" }, - {"{\"k0\":\"v0\"}", "", "{}" }, - {"{\"k0\":\"v0\"}", "k1", "{}" }, - {"{\"k0\":\"v0\"}", new String[]{}, "{}" }, - {"{\"k0\":\"v0\"}", new JSONArray(), "{}" }, - {"{\"k0\":\"v0\"}", new ArrayList(0), "{}" },//17 + {"{'k0':'v0'}", null, "{}" }, + {"{'k0':'v0'}", "", "{}" }, + {"{'k0':'v0'}", "k1", "{}" }, + {"{'k0':'v0'}", new String[]{}, "{}" }, + {"{'k0':'v0'}", new JSONArray(), "{}" }, + {"{'k0':'v0'}", new ArrayList(0), "{}" },//17 //simple json, valid/invalid keys - {"{\"k0\":\"v0\"}", "k0", "{\"k0\":\"v0\"}" }, - {"{\"k0\":\"v0\"}", "v0", "{}" }, - {"{\"k0\":\"v0\"}", "k0.k1", "{}" },//20 - {"{\"k0\":\"v0\"}", "k1.k0", "{}" }, - {"{\"k0\":null}", "k0", "{\"k0\":null}" }, - {"{\"k0\":null}", "v0", "{}" }, + {"{'k0':'v0'}", "k0", "{'k0':'v0'}" }, + {"{'k0':'v0'}", "v0", "{}" }, + {"{'k0':'v0'}", "k0.k1", "{}" },//20 + {"{'k0':'v0'}", "k1.k0", "{}" }, + {"{'k0':null}", "k0", "{'k0':null}" }, + {"{'k0':null}", "v0", "{}" }, //key with dot char - {"{\"k0.k1\":\"v0\"}", "k0", "{}" }, - {"{\"k0.k1\":\"v0\"}", "k1", "{}" }, - {"{\"k0.k1\":\"v0\"}", "k0.k1", "{}" }, + {"{'k0.k1':'v0'}", "k0", "{}" }, + {"{'k0.k1':'v0'}", "k1", "{}" }, + {"{'k0.k1':'v0'}", "k0.k1", "{}" }, // key with dot ambiguity - {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0", "{\"k0\":{}}" }, - {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k1", "{}" }, - {"{\"k0.k1\":\"withDot\",\"k0\":{\"k1\":null}}", "k0.k1", "{\"k0\":{\"k1\":null}}" }, - {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1", "{\"k0\":{\"k1\":{}}}" }, - {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k0.k1.k2", "{\"k0\":{\"k1\":{\"k2\":null}}}" }, - {"{\"k0\":{\"k1.k2\":\"dot\",\"k1\":{\"k2\":null}}}", "k1.k2", "{}" }, - {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k0", "{\"k0\":{}}}" }, - {"{\"k0\":{\"k1.k2\":\"dot\"},\"k1\":{\"k2\":\"v2\"}}}","k1.k2", "{\"k1\":{\"k2\":\"v2\"}}}" }, - {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2.k3.k4", "{}" }, - {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2.k3", "{}" }, - {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0.k2", "{\"k0\":{\"k2\":{}}}" }, - {"{\"k0\":{\"k1\":\"v1\",\"k2\":{\"k3.k4\":\"dot\"}}}", "k0", "{\"k0\":{}}" },//38 + {"{'k0.k1':'withDot','k0':{'k1':null}}", "k0", "{'k0':{}}" }, + {"{'k0.k1':'withDot','k0':{'k1':null}}", "k1", "{}" }, + {"{'k0.k1':'withDot','k0':{'k1':null}}", "k0.k1", "{'k0':{'k1':null}}" }, + {"{'k0':{'k1.k2':'dot','k1':{'k2':null}}}", "k0.k1", "{'k0':{'k1':{}}}" }, + {"{'k0':{'k1.k2':'dot','k1':{'k2':null}}}", "k0.k1.k2", "{'k0':{'k1':{'k2':null}}}" }, + {"{'k0':{'k1.k2':'dot','k1':{'k2':null}}}", "k1.k2", "{}" }, + {"{'k0':{'k1.k2':'dot'},'k1':{'k2':'v2'}}}", "k0", "{'k0':{}}}" }, + {"{'k0':{'k1.k2':'dot'},'k1':{'k2':'v2'}}}", "k1.k2", "{'k1':{'k2':'v2'}}}" }, + {"{'k0':{'k1':'v1','k2':{'k3.k4':'dot'}}}", "k0.k2.k3.k4", "{}" }, + {"{'k0':{'k1':'v1','k2':{'k3.k4':'dot'}}}", "k0.k2.k3", "{}" }, + {"{'k0':{'k1':'v1','k2':{'k3.k4':'dot'}}}", "k0.k2", "{'k0':{'k2':{}}}" }, + {"{'k0':{'k1':'v1','k2':{'k3.k4':'dot'}}}", "k0", "{'k0':{}}" },//38 //ignore non-existent keys but keep good keys - {"{\"k0\":\"v0\",\"k1\":\"v1\"}", new String[]{"k0","k2"}, "{\"k0\":\"v0\"}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k2"}, "{\"k0\":\"v0\"}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2"}, "{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k0.k2"}, "{\"k0\":\"v0\"}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1.k2","k1"}, "{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1"}, "{\"k0\":\"v0\",\"k1\":{}}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0","k1","k2"}, "{\"k0\":\"v0\",\"k1\":{}}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2"}, "{\"k1\":{\"k2\":\"v2\"}}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k2.k3"}, "{}" }, - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k0.k1.k2"}, "{}" },//48 - {"{\"k0\":\"v0\",\"k1\":{\"k2\":\"v2\"}}", new String[]{"k1.k0"}, "{}" }, + {"{'k0':'v0','k1':'v1'}", new String[]{"k0","k2"}, "{'k0':'v0'}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0","k2"}, "{'k0':'v0'}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0","k1.k2"}, "{'k0':'v0','k1':{'k2':'v2'}}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0","k0.k2"}, "{'k0':'v0'}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0","k1.k2","k1"}, "{'k0':'v0','k1':{'k2':'v2'}}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0","k1"}, "{'k0':'v0','k1':{}}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0","k1","k2"}, "{'k0':'v0','k1':{}}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k1.k2"}, "{'k1':{'k2':'v2'}}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k1.k2.k3"}, "{}" }, + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k0.k1.k2"}, "{}" },//48 + {"{'k0':'v0','k1':{'k2':'v2'}}", new String[]{"k1.k0"}, "{}" }, //arrays - key inside array treated as child - {"{\"k0\":{\"k1\":[1,2,3,4]}}", "k0", "{\"k0\":{}}" }, - {"{\"k0\":{\"k1\":[1,2,3,4]}}", "k0.k1", "{\"k0\":{\"k1\":[1,2,3,4]}}" }, - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0", "{\"k0\":{}}" }, - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", "{\"k0\":{\"k1\":[1,{},3,4]}}" }, - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1", "{\"k0\":{\"k1\":[{},{}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"},{\"k2\":\"v2\"}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":\"v4\"}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":\"v4\"}]}}", "k0.k3.k4", "{\"k0\":{\"k3\":[{\"k4\":\"v4\"}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[{\"k2\":\"v2\"}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", "k0.k3.k4", "{\"k0\":{\"k3\":[{\"k4\":{}}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", "k0.k3.k4.k5", "{\"k0\":{\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", new String[]{"k0.k1", "k0.k3"}, "{\"k0\":{\"k3\":[{}],\"k1\":[{}]}}" }, - {"{\"k0\":{\"k1\":[{\"k2\":\"v2\"}],\"k3\":[{\"k4\":{\"k5\":\"v5\"}}]}}", new String[]{"k0.k1", "k0.k3.k4.k5"}, "{\"k0\":{\"k3\":[{\"k4\":{\"k5\":\"v5\"}}],\"k1\":[{}]}}" }, + {"{'k0':{'k1':[1,2,3,4]}}", "k0", "{'k0':{}}" }, + {"{'k0':{'k1':[1,2,3,4]}}", "k0.k1", "{'k0':{'k1':[1,2,3,4]}}" }, + {"{'k0':{'k1':[1,{'k2':'v2'},3,4]}}", "k0", "{'k0':{}}" }, + {"{'k0':{'k1':[1,{'k2':'v2'},3,4]}}", "k0.k1", "{'k0':{'k1':[1,{},3,4]}}" }, + {"{'k0':{'k1':[1,{'k2':'v2'},3,4]}}", "k0.k1.k2", "{'k0':{'k1':[{'k2':'v2'}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'},{'k2':'v2'}]}}", "k0.k1", "{'k0':{'k1':[{},{}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'},{'k2':'v2'}]}}", "k0.k1.k2", "{'k0':{'k1':[{'k2':'v2'},{'k2':'v2'}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':'v4'}]}}", "k0.k1.k2", "{'k0':{'k1':[{'k2':'v2'}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':'v4'}]}}", "k0.k3.k4", "{'k0':{'k3':[{'k4':'v4'}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':{'k5':'v5'}}]}}", "k0.k1.k2", "{'k0':{'k1':[{'k2':'v2'}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':{'k5':'v5'}}]}}", "k0.k3.k4", "{'k0':{'k3':[{'k4':{}}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':{'k5':'v5'}}]}}", "k0.k3.k4.k5", "{'k0':{'k3':[{'k4':{'k5':'v5'}}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':{'k5':'v5'}}]}}", new String[]{"k0.k1", "k0.k3"}, "{'k0':{'k3':[{}],'k1':[{}]}}" }, + {"{'k0':{'k1':[{'k2':'v2'}],'k3':[{'k4':{'k5':'v5'}}]}}", new String[]{"k0.k1", "k0.k3.k4.k5"}, "{'k0':{'k3':[{'k4':{'k5':'v5'}}],'k1':[{}]}}" }, }); } From eacbfb9457067272afb0ac1187a4bf015f3a8ac5 Mon Sep 17 00:00:00 2001 From: UrielCh Date: Sat, 24 Sep 2016 07:51:33 -0700 Subject: [PATCH 15/18] smal improvement --- .../main/java/net/minidev/json/actions/path/PathDelimiter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java index 178f3a2d..b22fea88 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java +++ b/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java @@ -13,7 +13,7 @@ public abstract class PathDelimiter { public PathDelimiter(char delim) { this.delimChar = delim; - this.delimStr = "" + delim; + this.delimStr = String.valueOf(delim); } public PathDelimiter withAcceptDelimiterInNodeName(boolean acceptDelimInKey) { From b5c2da1624f480f37699d4d9c770eb1ef15f8031 Mon Sep 17 00:00:00 2001 From: UrielCh Date: Sat, 24 Sep 2016 08:07:17 -0700 Subject: [PATCH 16/18] move action to json-smart-action --- json-smart-action/.gitignore | 1 + json-smart-action/pom.xml | 259 +++++++++ .../minidev/json/actions/ElementRemover.java | 92 ++-- .../net/minidev/json/actions/PathLocator.java | 130 ++--- .../net/minidev/json/actions/PathRemover.java | 130 ++--- .../minidev/json/actions/PathReplicator.java | 0 .../minidev/json/actions/PathsRetainer.java | 0 .../actions/navigate/CopyPathsAction.java | 0 .../actions/navigate/JSONNavigateAction.java | 0 .../json/actions/navigate/JSONNavigator.java | 0 .../json/actions/navigate/NavigateAction.java | 0 .../json/actions/navigate/TreeNavigator.java | 0 .../json/actions/navigate/package-info.java | 0 .../json/actions/path/DotDelimiter.java | 0 .../json/actions/path/PathDelimiter.java | 0 .../json/actions/path/SlashDelimiter.java | 0 .../minidev/json/actions/path/TreePath.java | 0 .../actions/traverse/JSONTraverseAction.java | 0 .../json/actions/traverse/JSONTraverser.java | 62 +-- .../actions/traverse/KeysPrintAction.java | 0 .../traverse/LocatePathsJsonAction.java | 0 .../traverse/RemoveElementsJsonAction.java | 0 .../traverse/RemovePathsJsonAction.java | 0 .../traverse/RetainPathsJsonAction.java | 0 .../actions/traverse/TreeTraverseAction.java | 0 .../json/actions/traverse/TreeTraverser.java | 180 +++---- .../json/actions/traverse/package-info.java | 0 .../json/test/actions/ElementRemoverTest.java | 214 ++++---- .../test/actions/KeysPrintActionTest.java | 0 .../json/test/actions/PathLocatorTest.java | 0 .../json/test/actions/PathRemoverTest.java | 234 ++++---- .../json/test/actions/PathReplicatorTest.java | 0 .../json/test/actions/PathsRetainerTest.java | 0 .../json/test/actions/TreePathTest.java | 0 json-smart/pom.xml | 502 +++++++++--------- parent/pom.xml | 22 +- 36 files changed, 1038 insertions(+), 788 deletions(-) create mode 100644 json-smart-action/.gitignore create mode 100644 json-smart-action/pom.xml rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/ElementRemover.java (97%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/PathLocator.java (97%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/PathRemover.java (97%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/PathReplicator.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/PathsRetainer.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/navigate/package-info.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/path/DotDelimiter.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/path/PathDelimiter.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/path/TreePath.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java (96%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java (100%) rename json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java => json-smart-action/src/main/java/net/minidev/json/actions/traverse/LocatePathsJsonAction.java (100%) rename json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java => json-smart-action/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJsonAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java (100%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java (96%) rename {json-smart => json-smart-action}/src/main/java/net/minidev/json/actions/traverse/package-info.java (100%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java (97%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java (100%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java (100%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java (98%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java (100%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java (100%) rename {json-smart => json-smart-action}/src/test/java/net/minidev/json/test/actions/TreePathTest.java (100%) diff --git a/json-smart-action/.gitignore b/json-smart-action/.gitignore new file mode 100644 index 00000000..b83d2226 --- /dev/null +++ b/json-smart-action/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/json-smart-action/pom.xml b/json-smart-action/pom.xml new file mode 100644 index 00000000..5ac42754 --- /dev/null +++ b/json-smart-action/pom.xml @@ -0,0 +1,259 @@ + + + + net.minidev + minidev-parent + 2.2.1-b-SNAPSHOT + + 4.0.0 + json-smart-action + JSON Small and Fast Parser + + JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. + + bundle + http://www.minidev.net/ + + Chemouni Uriel + http://www.minidev.net/ + + + + uriel + Uriel Chemouni + uchemouni@gmail.com + GMT+1 + + + + + erav + Eitan Raviv + adoneitan@gmail.com + GMT+2 + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + All files under Apache 2 + + + + UTF-8 + 1.5 + 1.5 + + + + junit + junit + test + + + net.minidev + json-smart + + + + + scm:git:https://github.com/netplex/json-smart-v2.git + scm:git:https://github.com/netplex/json-smart-v2.git + https://github.com/netplex/json-smart-v2 + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + release-sign-artifacts + + + + performRelease + true + + + + + 2C8DF6EC + + + + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.2 + + forked-path + -Psonatype-oss-release + false + false + release + deploy + + + + + + + include-sources + + + + / + true + src/main/java + + **/*.java + + + + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + bind-sources + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + UTF-8 + 1.6 + 1.6 + + **/.svn/* + **/.svn + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + UTF-8 + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + **/.svn/* + **/.svn + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + false + + + + + attach-javadocs + + jar + + + + + + org.apache.felix + maven-bundle-plugin + 3.0.0 + true + + + ${project.groupId}.${project.artifactId} + ${project.artifactId} + ${project.version} + + net.minidev.json, net.minidev.json.annotate, net.minidev.json.parser, net.minidev.json.reader, net.minidev.json.writer + + + + + + + \ No newline at end of file diff --git a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java b/json-smart-action/src/main/java/net/minidev/json/actions/ElementRemover.java similarity index 97% rename from json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java rename to json-smart-action/src/main/java/net/minidev/json/actions/ElementRemover.java index 663b6e26..d34a8346 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/ElementRemover.java +++ b/json-smart-action/src/main/java/net/minidev/json/actions/ElementRemover.java @@ -1,46 +1,46 @@ -package net.minidev.json.actions; - -import net.minidev.json.JSONObject; -import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.RemoveElementsJsonAction; -import net.minidev.json.actions.traverse.JSONTraverseAction; - -import java.util.*; - -/** - * Removes key:value elements from every node of a {@link JSONObject} matching the list of user-specified elements. - *

- * An element to remove must be specified as a key:value pair - *

- * Usage Example: - *

- * To remove the element k2:v2 from the {@link JSONObject} {k0:{k2:v2, k3:v3}, k1:{k2:v2, k4:v4}} use the remover like so: - *

- * PathRemover pr = new PathRemover("k2.v2");
- * JSONObject cleanObject = pr.remove(new JSONObject(...));
- * 
- * The resulting object 'cleanObject' would be {k0:{k3:v3}, k1:{k4:v4}} - *

- * See unit tests for more examples - * - * @author adoneitan@gmail.com - * - */ -public class ElementRemover { - private Map elementsToRemove; - - public ElementRemover(Map elementsToRemove) { - this.elementsToRemove = elementsToRemove == null ? Collections. emptyMap() : elementsToRemove; - } - - public ElementRemover(JSONObject elementsToRemove) { - this.elementsToRemove = elementsToRemove == null ? Collections. emptyMap() : elementsToRemove; - } - - public JSONObject remove(JSONObject objectToClean) { - JSONTraverseAction strategy = new RemoveElementsJsonAction(this.elementsToRemove); - JSONTraverser traversal = new JSONTraverser(strategy); - traversal.traverse(objectToClean); - return (JSONObject) strategy.result(); - } -} +package net.minidev.json.actions; + +import net.minidev.json.JSONObject; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.RemoveElementsJsonAction; +import net.minidev.json.actions.traverse.JSONTraverseAction; + +import java.util.*; + +/** + * Removes key:value elements from every node of a {@link JSONObject} matching the list of user-specified elements. + *

+ * An element to remove must be specified as a key:value pair + *

+ * Usage Example: + *

+ * To remove the element k2:v2 from the {@link JSONObject} {k0:{k2:v2, k3:v3}, k1:{k2:v2, k4:v4}} use the remover like so: + *

+ * PathRemover pr = new PathRemover("k2.v2");
+ * JSONObject cleanObject = pr.remove(new JSONObject(...));
+ * 
+ * The resulting object 'cleanObject' would be {k0:{k3:v3}, k1:{k4:v4}} + *

+ * See unit tests for more examples + * + * @author adoneitan@gmail.com + * + */ +public class ElementRemover { + private Map elementsToRemove; + + public ElementRemover(Map elementsToRemove) { + this.elementsToRemove = elementsToRemove == null ? Collections. emptyMap() : elementsToRemove; + } + + public ElementRemover(JSONObject elementsToRemove) { + this.elementsToRemove = elementsToRemove == null ? Collections. emptyMap() : elementsToRemove; + } + + public JSONObject remove(JSONObject objectToClean) { + JSONTraverseAction strategy = new RemoveElementsJsonAction(this.elementsToRemove); + JSONTraverser traversal = new JSONTraverser(strategy); + traversal.traverse(objectToClean); + return (JSONObject) strategy.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java b/json-smart-action/src/main/java/net/minidev/json/actions/PathLocator.java similarity index 97% rename from json-smart/src/main/java/net/minidev/json/actions/PathLocator.java rename to json-smart-action/src/main/java/net/minidev/json/actions/PathLocator.java index ada5d9d5..f62efb51 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/PathLocator.java +++ b/json-smart-action/src/main/java/net/minidev/json/actions/PathLocator.java @@ -1,65 +1,65 @@ -package net.minidev.json.actions; - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.DotDelimiter; -import net.minidev.json.actions.path.PathDelimiter; -import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.LocatePathsJsonAction; -import net.minidev.json.actions.traverse.JSONTraverseAction; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * Searches for paths in a {@link JSONObject} and returns those found. - *

- * Traverses the specified {@link JSONObject} searching for nodes whose paths (from the root down) match - * any of the user-specified paths. The paths that match are returned. - *

- * A path to locate must be specified in the n-gram format - a list of keys from the root down separated by dots: - * K0[[[[.K1].K2].K3]...] - *
- * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are - * not supported. - *

- * - * @author adoneitan@gmail.com - */ -public class PathLocator { - protected List pathsToFind; - protected PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); - - public PathLocator(JSONArray pathsToFind) { - if (pathsToFind == null || pathsToFind.isEmpty()) { - this.pathsToFind = Collections.emptyList(); - } else { - this.pathsToFind = new ArrayList(); - for (Object s : pathsToFind) { - this.pathsToFind.add((String) s); - } - } - } - - public PathLocator(List pathsToFind) { - this.pathsToFind = pathsToFind == null || pathsToFind.size() == 0 ? Collections. emptyList() : pathsToFind; - } - - public PathLocator(String... pathsToFind) { - this.pathsToFind = pathsToFind == null || pathsToFind.length == 0 ? Collections. emptyList() : Arrays.asList(pathsToFind); - } - - public PathLocator with(PathDelimiter pathDelimiter) { - this.pathDelimiter = pathDelimiter; - return this; - } - - public List locate(JSONObject object) { - JSONTraverseAction action = new LocatePathsJsonAction(this.pathsToFind, pathDelimiter); - JSONTraverser traversal = new JSONTraverser(action).with(pathDelimiter); - traversal.traverse(object); - return (List) action.result(); - } -} +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.PathDelimiter; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.LocatePathsJsonAction; +import net.minidev.json.actions.traverse.JSONTraverseAction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Searches for paths in a {@link JSONObject} and returns those found. + *

+ * Traverses the specified {@link JSONObject} searching for nodes whose paths (from the root down) match + * any of the user-specified paths. The paths that match are returned. + *

+ * A path to locate must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * + * @author adoneitan@gmail.com + */ +public class PathLocator { + protected List pathsToFind; + protected PathDelimiter pathDelimiter = new DotDelimiter().withAcceptDelimiterInNodeName(false); + + public PathLocator(JSONArray pathsToFind) { + if (pathsToFind == null || pathsToFind.isEmpty()) { + this.pathsToFind = Collections.emptyList(); + } else { + this.pathsToFind = new ArrayList(); + for (Object s : pathsToFind) { + this.pathsToFind.add((String) s); + } + } + } + + public PathLocator(List pathsToFind) { + this.pathsToFind = pathsToFind == null || pathsToFind.size() == 0 ? Collections. emptyList() : pathsToFind; + } + + public PathLocator(String... pathsToFind) { + this.pathsToFind = pathsToFind == null || pathsToFind.length == 0 ? Collections. emptyList() : Arrays.asList(pathsToFind); + } + + public PathLocator with(PathDelimiter pathDelimiter) { + this.pathDelimiter = pathDelimiter; + return this; + } + + public List locate(JSONObject object) { + JSONTraverseAction action = new LocatePathsJsonAction(this.pathsToFind, pathDelimiter); + JSONTraverser traversal = new JSONTraverser(action).with(pathDelimiter); + traversal.traverse(object); + return (List) action.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java b/json-smart-action/src/main/java/net/minidev/json/actions/PathRemover.java similarity index 97% rename from json-smart/src/main/java/net/minidev/json/actions/PathRemover.java rename to json-smart-action/src/main/java/net/minidev/json/actions/PathRemover.java index f872445c..af486e3a 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/PathRemover.java +++ b/json-smart-action/src/main/java/net/minidev/json/actions/PathRemover.java @@ -1,65 +1,65 @@ -package net.minidev.json.actions; - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.actions.traverse.JSONTraverser; -import net.minidev.json.actions.traverse.RemovePathsJsonAction; -import net.minidev.json.actions.traverse.JSONTraverseAction; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * Removes branches of nodes from a {@link JSONObject} matching the list of user-specified paths. - *

- * A path to remove must be specified in the n-gram format - a list of keys from the root down separated by dots: - * K0[[[[.K1].K2].K3]...] - *
- * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are - * not supported. - *

- * Usage Example: - *

- * To remove the field k1.k2 from the {@link JSONObject} {k1:{k2:v2}, k3:{k4:v4}} use the remover like so: - *

- * PathRemover pr = new PathRemover("k1.k2");
- * JSONObject cleanObject = pr.remove(new JSONObject(...));
- * 
- * The resulting object 'cleanObject' would be {k1:{k3:{k4:v4}}} - *

- * See unit tests for more examples - * - * @author adoneitan@gmail.com - * - */ -public class PathRemover { - protected List pathsToRemove; - - public PathRemover(JSONArray pathsToRemove) { - if (pathsToRemove == null || pathsToRemove.isEmpty()) { - this.pathsToRemove = Collections.emptyList(); - } else { - this.pathsToRemove = new ArrayList(); - for (Object s : pathsToRemove) { - this.pathsToRemove.add((String) s); - } - } - } - - public PathRemover(List pathsToRemove) { - this.pathsToRemove = pathsToRemove == null || pathsToRemove.size() == 0 ? Collections. emptyList() : pathsToRemove; - } - - public PathRemover(String... pathsToRemove) { - this.pathsToRemove = pathsToRemove == null || pathsToRemove.length == 0 ? Collections. emptyList() : Arrays.asList(pathsToRemove); - } - - public JSONObject remove(JSONObject objectToClean) { - JSONTraverseAction strategy = new RemovePathsJsonAction(this.pathsToRemove); - JSONTraverser traversal = new JSONTraverser(strategy); - traversal.traverse(objectToClean); - return (JSONObject) strategy.result(); - } -} +package net.minidev.json.actions; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.traverse.JSONTraverser; +import net.minidev.json.actions.traverse.RemovePathsJsonAction; +import net.minidev.json.actions.traverse.JSONTraverseAction; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Removes branches of nodes from a {@link JSONObject} matching the list of user-specified paths. + *

+ * A path to remove must be specified in the n-gram format - a list of keys from the root down separated by dots: + * K0[[[[.K1].K2].K3]...] + *
+ * A key to the right of a dot is a direct child of a key to the left of a dot. Keys with a dot in their name are + * not supported. + *

+ * Usage Example: + *

+ * To remove the field k1.k2 from the {@link JSONObject} {k1:{k2:v2}, k3:{k4:v4}} use the remover like so: + *

+ * PathRemover pr = new PathRemover("k1.k2");
+ * JSONObject cleanObject = pr.remove(new JSONObject(...));
+ * 
+ * The resulting object 'cleanObject' would be {k1:{k3:{k4:v4}}} + *

+ * See unit tests for more examples + * + * @author adoneitan@gmail.com + * + */ +public class PathRemover { + protected List pathsToRemove; + + public PathRemover(JSONArray pathsToRemove) { + if (pathsToRemove == null || pathsToRemove.isEmpty()) { + this.pathsToRemove = Collections.emptyList(); + } else { + this.pathsToRemove = new ArrayList(); + for (Object s : pathsToRemove) { + this.pathsToRemove.add((String) s); + } + } + } + + public PathRemover(List pathsToRemove) { + this.pathsToRemove = pathsToRemove == null || pathsToRemove.size() == 0 ? Collections. emptyList() : pathsToRemove; + } + + public PathRemover(String... pathsToRemove) { + this.pathsToRemove = pathsToRemove == null || pathsToRemove.length == 0 ? Collections. emptyList() : Arrays.asList(pathsToRemove); + } + + public JSONObject remove(JSONObject objectToClean) { + JSONTraverseAction strategy = new RemovePathsJsonAction(this.pathsToRemove); + JSONTraverser traversal = new JSONTraverser(strategy); + traversal.traverse(objectToClean); + return (JSONObject) strategy.result(); + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java b/json-smart-action/src/main/java/net/minidev/json/actions/PathReplicator.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/PathReplicator.java rename to json-smart-action/src/main/java/net/minidev/json/actions/PathReplicator.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java b/json-smart-action/src/main/java/net/minidev/json/actions/PathsRetainer.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/PathsRetainer.java rename to json-smart-action/src/main/java/net/minidev/json/actions/PathsRetainer.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/navigate/CopyPathsAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/navigate/JSONNavigateAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java b/json-smart-action/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java rename to json-smart-action/src/main/java/net/minidev/json/actions/navigate/JSONNavigator.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/navigate/NavigateAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java b/json-smart-action/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java rename to json-smart-action/src/main/java/net/minidev/json/actions/navigate/TreeNavigator.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java b/json-smart-action/src/main/java/net/minidev/json/actions/navigate/package-info.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/navigate/package-info.java rename to json-smart-action/src/main/java/net/minidev/json/actions/navigate/package-info.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java b/json-smart-action/src/main/java/net/minidev/json/actions/path/DotDelimiter.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/path/DotDelimiter.java rename to json-smart-action/src/main/java/net/minidev/json/actions/path/DotDelimiter.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java b/json-smart-action/src/main/java/net/minidev/json/actions/path/PathDelimiter.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/path/PathDelimiter.java rename to json-smart-action/src/main/java/net/minidev/json/actions/path/PathDelimiter.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java b/json-smart-action/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java rename to json-smart-action/src/main/java/net/minidev/json/actions/path/SlashDelimiter.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java b/json-smart-action/src/main/java/net/minidev/json/actions/path/TreePath.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/path/TreePath.java rename to json-smart-action/src/main/java/net/minidev/json/actions/path/TreePath.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/JSONTraverseAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java similarity index 96% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java index f2cc7594..506526cb 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java +++ b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/JSONTraverser.java @@ -1,31 +1,31 @@ -package net.minidev.json.actions.traverse; - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.actions.path.DotDelimiter; -import net.minidev.json.actions.path.PathDelimiter; - -/** - * Traverses every node of a {@link JSONObject} - *

- * {@link JSONTraverser} accepts an action and provides callback hooks for it to act - * on the traversed nodes at each significant step. See {@link JSONTraverseAction}. - *

- * A key to the right of a dot is a direct child of a key to the left of a dot. - * Keys with a dot in their name are not supported. - *

- * See package-info for more details - * - * @author adoneitan@gmail.com - * - */ -public class JSONTraverser extends TreeTraverser { - public JSONTraverser(JSONTraverseAction action) { - super(action, new DotDelimiter()); - } - - public JSONTraverser with(PathDelimiter delim) { - super.delim = delim; - return this; - } -} +package net.minidev.json.actions.traverse; + +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.actions.path.DotDelimiter; +import net.minidev.json.actions.path.PathDelimiter; + +/** + * Traverses every node of a {@link JSONObject} + *

+ * {@link JSONTraverser} accepts an action and provides callback hooks for it to act + * on the traversed nodes at each significant step. See {@link JSONTraverseAction}. + *

+ * A key to the right of a dot is a direct child of a key to the left of a dot. + * Keys with a dot in their name are not supported. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + * + */ +public class JSONTraverser extends TreeTraverser { + public JSONTraverser(JSONTraverseAction action) { + super(action, new DotDelimiter()); + } + + public JSONTraverser with(PathDelimiter delim) { + super.delim = delim; + return this; + } +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/KeysPrintAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/LocatePathsJsonAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/LocatePathsJSONAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/LocatePathsJsonAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJsonAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJSONAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/RemoveElementsJsonAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/RemovePathsJsonAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/RetainPathsJsonAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/TreeTraverseAction.java diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java similarity index 96% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java index ff3cea3c..77f9085f 100644 --- a/json-smart/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java +++ b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/TreeTraverser.java @@ -1,90 +1,90 @@ -package net.minidev.json.actions.traverse; - -import net.minidev.json.actions.path.PathDelimiter; - -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -/** - * Traverses every node of a tree made up of a combination of {@link Map}s and {@link List}s - *

- * {@link TreeTraverser} accepts an action and provides callback hooks for it to act - * on the traversed nodes at each significant step. See {@link TreeTraverseAction}. - *

- * See package-info for more details - * - * @author adoneitan@gmail.com - * - */ -public class TreeTraverser, L extends List> { - protected TreeTraverseAction action; - protected PathDelimiter delim; - protected String pathPrefix = ""; - - public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) { - this.action = action; - this.delim = delim; - } - - public TreeTraverser with(String pathPrefix) { - this.pathPrefix = pathPrefix; - return this; - } - - public void traverse(M map) { - if (action.start(map)) { - depthFirst(pathPrefix, map); - } - action.end(); - } - - private void depthFirst(String fullPath, M map) { - if (map == null || map.entrySet() == null || !action.recurInto(fullPath, map)) { - return; - } - Iterator> it = map.entrySet().iterator(); - while (it.hasNext()) { - Entry entry = it.next(); - String fullPathToEntry = buildPath(fullPath, entry.getKey()); - - if (!action.traverseEntry(fullPathToEntry, entry)) { - continue; - } else if (action.removeEntry(fullPathToEntry, entry)) { - it.remove(); - continue; - } - - if (entry.getValue() instanceof Map) { - depthFirst(fullPathToEntry, (M) entry.getValue()); - } else if (entry.getValue() instanceof List) { - depthFirst(fullPathToEntry, (L) entry.getValue()); - } else { - action.handleLeaf(fullPathToEntry, entry); - } - } - } - - private void depthFirst(String fullPath, L list) { - if (!action.recurInto(fullPath, (L) list)) { - return; - } - int listIndex = 0; - for (Object listItem : list.toArray()) { - if (listItem instanceof Map) { - depthFirst(fullPath, (M) listItem); - } else if (listItem instanceof List) { - depthFirst(fullPath, (L) listItem); - } else { - action.handleLeaf(fullPath, listIndex, listItem); - } - listIndex++; - } - } - - private String buildPath(String fullPath, String entryKey) { - return pathPrefix.equals(fullPath) ? pathPrefix + entryKey : fullPath + delim.str() + entryKey; - } - -} +package net.minidev.json.actions.traverse; + +import net.minidev.json.actions.path.PathDelimiter; + +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * Traverses every node of a tree made up of a combination of {@link Map}s and {@link List}s + *

+ * {@link TreeTraverser} accepts an action and provides callback hooks for it to act + * on the traversed nodes at each significant step. See {@link TreeTraverseAction}. + *

+ * See package-info for more details + * + * @author adoneitan@gmail.com + * + */ +public class TreeTraverser, L extends List> { + protected TreeTraverseAction action; + protected PathDelimiter delim; + protected String pathPrefix = ""; + + public TreeTraverser(TreeTraverseAction action, PathDelimiter delim) { + this.action = action; + this.delim = delim; + } + + public TreeTraverser with(String pathPrefix) { + this.pathPrefix = pathPrefix; + return this; + } + + public void traverse(M map) { + if (action.start(map)) { + depthFirst(pathPrefix, map); + } + action.end(); + } + + private void depthFirst(String fullPath, M map) { + if (map == null || map.entrySet() == null || !action.recurInto(fullPath, map)) { + return; + } + Iterator> it = map.entrySet().iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + String fullPathToEntry = buildPath(fullPath, entry.getKey()); + + if (!action.traverseEntry(fullPathToEntry, entry)) { + continue; + } else if (action.removeEntry(fullPathToEntry, entry)) { + it.remove(); + continue; + } + + if (entry.getValue() instanceof Map) { + depthFirst(fullPathToEntry, (M) entry.getValue()); + } else if (entry.getValue() instanceof List) { + depthFirst(fullPathToEntry, (L) entry.getValue()); + } else { + action.handleLeaf(fullPathToEntry, entry); + } + } + } + + private void depthFirst(String fullPath, L list) { + if (!action.recurInto(fullPath, (L) list)) { + return; + } + int listIndex = 0; + for (Object listItem : list.toArray()) { + if (listItem instanceof Map) { + depthFirst(fullPath, (M) listItem); + } else if (listItem instanceof List) { + depthFirst(fullPath, (L) listItem); + } else { + action.handleLeaf(fullPath, listIndex, listItem); + } + listIndex++; + } + } + + private String buildPath(String fullPath, String entryKey) { + return pathPrefix.equals(fullPath) ? pathPrefix + entryKey : fullPath + delim.str() + entryKey; + } + +} diff --git a/json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java b/json-smart-action/src/main/java/net/minidev/json/actions/traverse/package-info.java similarity index 100% rename from json-smart/src/main/java/net/minidev/json/actions/traverse/package-info.java rename to json-smart-action/src/main/java/net/minidev/json/actions/traverse/package-info.java diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java similarity index 97% rename from json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java index 5a8113bf..c71aeac4 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java +++ b/json-smart-action/src/test/java/net/minidev/json/test/actions/ElementRemoverTest.java @@ -1,107 +1,107 @@ -package net.minidev.json.test.actions; - -import net.minidev.json.JSONObject; -import net.minidev.json.JSONValue; -import net.minidev.json.actions.ElementRemover; -import net.minidev.json.parser.ParseException; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.*; - -import static org.junit.Assert.assertEquals; - -/** - * Tests {@link ElementRemover} - * - * @author adoneitan@gmail.com - */ -@RunWith(Parameterized.class) -public class ElementRemoverTest { - private String jsonToClean; - private String elementsToRemove; - private String expectedJson; - - public ElementRemoverTest(String jsonToClean, String elementsToRemove, String expectedJson) { - this.jsonToClean = filter(jsonToClean); - this.elementsToRemove = filter(elementsToRemove); - this.expectedJson = filter(expectedJson); - } - - private static String filter(String test) { - if (test == null) - return null; - return test.replace("'", "\""); - } - - @Parameterized.Parameters - public static Collection params() { - List list = Arrays.asList(new String[][]{ - {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", null, "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, - {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{}", "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, - {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k0':'v2'}", "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, - {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k2':'v2'}", "{'k0':{},'k1':{'k3':'v3'}}"}, - {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k0':{'k2':'v2'}}", "{'k1':{'k2':'v2','k3':'v3'}}"}, - {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k2':'v2','k3':'v3'}", "{'k0':{},'k1':{}}"}, - {"{'k0':{}}", "{}", "{'k0':{}}"}, - }); - return list; - } - - @Test - public void test() throws ParseException { - JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; - JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson) : null; - JSONObject toRemove = elementsToRemove != null ? (JSONObject) JSONValue.parseWithException(elementsToRemove) : null; - ElementRemover er = new ElementRemover(toRemove); - er.remove(objectToClean); - assertEquals(expectedObject, objectToClean); - } - - // private ElementRemover switchKeyToRemove() - // { - // long m = System.currentTimeMillis(); - // if (elementsToRemove == null && m % 4 == 0) - // { - // System.out.println("cast to String"); - // return new ElementRemover((String)null); - // } - // else if (elementsToRemove == null && m % 4 == 1) - // { - // System.out.println("cast to String[]"); - // return new ElementRemover((String[])null); - // } - // else if (elementsToRemove == null && m % 4 == 2) - // { - // System.out.println("cast to JSONArray"); - // return new ElementRemover((JSONArray)null); - // } - // else if (elementsToRemove == null && m % 4 == 3) - // { - // System.out.println("cast to List"); - // return new ElementRemover((List)null); - // } - // else if (elementsToRemove instanceof String) - // { - // return new ElementRemover((String) elementsToRemove); - // } - // else if (elementsToRemove instanceof String[]) - // { - // return new ElementRemover((String[]) elementsToRemove); - // } - // else if (elementsToRemove instanceof JSONArray) - // { - // return new ElementRemover((JSONArray) elementsToRemove); - // } - // else if (elementsToRemove instanceof List) - // { - // return new ElementRemover((List) elementsToRemove); - // } - // else - // { - // throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); - // } - // } - -} +package net.minidev.json.test.actions; + +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.actions.ElementRemover; +import net.minidev.json.parser.ParseException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * Tests {@link ElementRemover} + * + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class ElementRemoverTest { + private String jsonToClean; + private String elementsToRemove; + private String expectedJson; + + public ElementRemoverTest(String jsonToClean, String elementsToRemove, String expectedJson) { + this.jsonToClean = filter(jsonToClean); + this.elementsToRemove = filter(elementsToRemove); + this.expectedJson = filter(expectedJson); + } + + private static String filter(String test) { + if (test == null) + return null; + return test.replace("'", "\""); + } + + @Parameterized.Parameters + public static Collection params() { + List list = Arrays.asList(new String[][]{ + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", null, "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{}", "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k0':'v2'}", "{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k2':'v2'}", "{'k0':{},'k1':{'k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k0':{'k2':'v2'}}", "{'k1':{'k2':'v2','k3':'v3'}}"}, + {"{'k0':{'k2':'v2'},'k1':{'k2':'v2','k3':'v3'}}", "{'k2':'v2','k3':'v3'}", "{'k0':{},'k1':{}}"}, + {"{'k0':{}}", "{}", "{'k0':{}}"}, + }); + return list; + } + + @Test + public void test() throws ParseException { + JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; + JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson) : null; + JSONObject toRemove = elementsToRemove != null ? (JSONObject) JSONValue.parseWithException(elementsToRemove) : null; + ElementRemover er = new ElementRemover(toRemove); + er.remove(objectToClean); + assertEquals(expectedObject, objectToClean); + } + + // private ElementRemover switchKeyToRemove() + // { + // long m = System.currentTimeMillis(); + // if (elementsToRemove == null && m % 4 == 0) + // { + // System.out.println("cast to String"); + // return new ElementRemover((String)null); + // } + // else if (elementsToRemove == null && m % 4 == 1) + // { + // System.out.println("cast to String[]"); + // return new ElementRemover((String[])null); + // } + // else if (elementsToRemove == null && m % 4 == 2) + // { + // System.out.println("cast to JSONArray"); + // return new ElementRemover((JSONArray)null); + // } + // else if (elementsToRemove == null && m % 4 == 3) + // { + // System.out.println("cast to List"); + // return new ElementRemover((List)null); + // } + // else if (elementsToRemove instanceof String) + // { + // return new ElementRemover((String) elementsToRemove); + // } + // else if (elementsToRemove instanceof String[]) + // { + // return new ElementRemover((String[]) elementsToRemove); + // } + // else if (elementsToRemove instanceof JSONArray) + // { + // return new ElementRemover((JSONArray) elementsToRemove); + // } + // else if (elementsToRemove instanceof List) + // { + // return new ElementRemover((List) elementsToRemove); + // } + // else + // { + // throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + // } + // } + +} diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java similarity index 100% rename from json-smart/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/KeysPrintActionTest.java diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java similarity index 100% rename from json-smart/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/PathLocatorTest.java diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java similarity index 98% rename from json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java index 73e62226..b50e9d97 100644 --- a/json-smart/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java +++ b/json-smart-action/src/test/java/net/minidev/json/test/actions/PathRemoverTest.java @@ -1,117 +1,117 @@ -package net.minidev.json.test.actions; - -import net.minidev.json.actions.PathRemover; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.JSONValue; -import net.minidev.json.parser.ParseException; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -import static org.junit.Assert.assertEquals; - -/** - * Tests {@link PathRemover} - * - * @author adoneitan@gmail.com - */ -@RunWith(Parameterized.class) -public class PathRemoverTest -{ - private String jsonToClean; - private Object keyToRemove; - private String expectedJson; - - public PathRemoverTest(String jsonToClean, Object keyToRemove, String expectedJson) - { - this.jsonToClean = jsonToClean; - this.keyToRemove = keyToRemove; - this.expectedJson = expectedJson; - } - - @Parameterized.Parameters - public static Collection params() { - return Arrays.asList(new Object[][]{ - {null, "key", null }, // null json - {"{}", "key", "{}" }, // empty json - {"{\"first\": null}", null, "{\"first\": null}" }, // null key - {"{\"first\": null}", "", "{\"first\": null}" }, // empty string key - {"{\"first\": null}", new String[]{}, "{\"first\": null}" }, // empty string array key - {"{\"first\": null}", new JSONArray(), "{\"first\": null}" }, // empty json array key - {"{\"first\": null}", new ArrayList(0), "{\"first\": null}" }, // empty list key - {"{\"first\": null}", "first", "{}" }, // remove root key - {"{\"first.f1\": null}", "first.f1", "{}" }, // key with dot - {"{\"first.f1\": \"withDot\", \"first\":{\"f1\": null}}", "first.f1", "{\"first\":{}}" }, //9 key with dot ambiguity - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{}}}}" }, // nested object remove single leaf - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "notfound", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, // nested object key does not exist - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{\"name\":\"me\"}}}}"}, // nested object remove first leaf - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.name", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, //13 nested object remove last leaf - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3", "{\"first\":{\"f2\":{}}}" }, // nested object remove intermediate node - {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first", "{}" }, // nested object remove root - {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2.id", "{\"first\":{\"f2\":[[1,{},3],4]}}" }, // double nested array remove leaf - {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2", "{\"first\":{}}" }, // double nested array remove array - {"{\"first\":[[1,{\"id\":\"id1\"},3],4]}", "first", "{}" }, // double nested array remove root - - //arrays - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", "{\"k0\":{}}" }, // value is array - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{},3,4]}}" }, // full path into array object - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.3" , "{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}" }, // full path into array primitive - {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{},{},3,4]}}" }, // full path into array with identical items - - // composite json remove all roots - {"{\"first\": {\"f2\":{\"id\":\"id1\"}}, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}", - (JSONArray) JSONValue.parse("[\"first\",\"second\",\"third\",\"id\"]"), - "{}" }, - // composite json remove all leaves - {"{\"first\": {\"f2\":{\"id\":\"id1\"}}, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}", - (List) Arrays.asList("first.f2.id", "second.k1.id", "second.id", "third", "id"), - "{\"first\": {\"f2\":{}}, \"second\": [{\"k1\":{}}, 4, 5, 6, {}]}" }, - - }); - } - - @Test - public void test() throws ParseException - { - JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; - JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson): null; - PathRemover cl = switchKeyToRemove(); - cl.remove(objectToClean); - assertEquals(expectedObject, objectToClean); - } - - private PathRemover switchKeyToRemove() - { - long m = System.currentTimeMillis(); - if (keyToRemove == null && m % 4 == 0) { - System.out.println("cast to String"); - return new PathRemover((String)null); - } else if (keyToRemove == null && m % 4 == 1) { - System.out.println("cast to String[]"); - return new PathRemover((String[])null); - } else if (keyToRemove == null && m % 4 == 2) { - System.out.println("cast to JSONArray"); - return new PathRemover((JSONArray)null); - } else if (keyToRemove == null && m % 4 == 3) { - System.out.println("cast to List"); - return new PathRemover((List)null); - } else if (keyToRemove instanceof String) { - return new PathRemover((String)keyToRemove); - } else if (keyToRemove instanceof String[]) { - return new PathRemover((String[])keyToRemove); - } else if (keyToRemove instanceof JSONArray) { - return new PathRemover((JSONArray)keyToRemove); - } else if (keyToRemove instanceof List) { - return new PathRemover((List)keyToRemove); - } else { - throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); - } - } - -} +package net.minidev.json.test.actions; + +import net.minidev.json.actions.PathRemover; +import net.minidev.json.JSONArray; +import net.minidev.json.JSONObject; +import net.minidev.json.JSONValue; +import net.minidev.json.parser.ParseException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * Tests {@link PathRemover} + * + * @author adoneitan@gmail.com + */ +@RunWith(Parameterized.class) +public class PathRemoverTest +{ + private String jsonToClean; + private Object keyToRemove; + private String expectedJson; + + public PathRemoverTest(String jsonToClean, Object keyToRemove, String expectedJson) + { + this.jsonToClean = jsonToClean; + this.keyToRemove = keyToRemove; + this.expectedJson = expectedJson; + } + + @Parameterized.Parameters + public static Collection params() { + return Arrays.asList(new Object[][]{ + {null, "key", null }, // null json + {"{}", "key", "{}" }, // empty json + {"{\"first\": null}", null, "{\"first\": null}" }, // null key + {"{\"first\": null}", "", "{\"first\": null}" }, // empty string key + {"{\"first\": null}", new String[]{}, "{\"first\": null}" }, // empty string array key + {"{\"first\": null}", new JSONArray(), "{\"first\": null}" }, // empty json array key + {"{\"first\": null}", new ArrayList(0), "{\"first\": null}" }, // empty list key + {"{\"first\": null}", "first", "{}" }, // remove root key + {"{\"first.f1\": null}", "first.f1", "{}" }, // key with dot + {"{\"first.f1\": \"withDot\", \"first\":{\"f1\": null}}", "first.f1", "{\"first\":{}}" }, //9 key with dot ambiguity + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{}}}}" }, // nested object remove single leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}", "notfound", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, // nested object key does not exist + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.id", "{\"first\":{\"f2\":{\"f3\":{\"name\":\"me\"}}}}"}, // nested object remove first leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3.name", "{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\"}}}}" }, //13 nested object remove last leaf + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first.f2.f3", "{\"first\":{\"f2\":{}}}" }, // nested object remove intermediate node + {"{\"first\":{\"f2\":{\"f3\":{\"id\":\"id1\",\"name\":\"me\"}}}}", "first", "{}" }, // nested object remove root + {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2.id", "{\"first\":{\"f2\":[[1,{},3],4]}}" }, // double nested array remove leaf + {"{\"first\":{\"f2\":[[1,{\"id\":\"id1\"},3],4]}}", "first.f2", "{\"first\":{}}" }, // double nested array remove array + {"{\"first\":[[1,{\"id\":\"id1\"},3],4]}", "first", "{}" }, // double nested array remove root + + //arrays + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1", "{\"k0\":{}}" }, // value is array + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{},3,4]}}" }, // full path into array object + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}", "k0.k1.3" , "{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},3,4]}}" }, // full path into array primitive + {"{\"k0\":{\"k1\":[1,{\"k2\":\"v2\"},{\"k2\":\"v2\"},3,4]}}", "k0.k1.k2", "{\"k0\":{\"k1\":[1,{},{},3,4]}}" }, // full path into array with identical items + + // composite json remove all roots + {"{\"first\": {\"f2\":{\"id\":\"id1\"}}, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}", + (JSONArray) JSONValue.parse("[\"first\",\"second\",\"third\",\"id\"]"), + "{}" }, + // composite json remove all leaves + {"{\"first\": {\"f2\":{\"id\":\"id1\"}}, \"second\": [{\"k1\":{\"id\":\"id1\"}}, 4, 5, 6, {\"id\": 123}], \"third\": 789, \"id\": null}", + (List) Arrays.asList("first.f2.id", "second.k1.id", "second.id", "third", "id"), + "{\"first\": {\"f2\":{}}, \"second\": [{\"k1\":{}}, 4, 5, 6, {}]}" }, + + }); + } + + @Test + public void test() throws ParseException + { + JSONObject objectToClean = jsonToClean != null ? (JSONObject) JSONValue.parseWithException(jsonToClean) : null; + JSONObject expectedObject = expectedJson != null ? (JSONObject) JSONValue.parseWithException(expectedJson): null; + PathRemover cl = switchKeyToRemove(); + cl.remove(objectToClean); + assertEquals(expectedObject, objectToClean); + } + + private PathRemover switchKeyToRemove() + { + long m = System.currentTimeMillis(); + if (keyToRemove == null && m % 4 == 0) { + System.out.println("cast to String"); + return new PathRemover((String)null); + } else if (keyToRemove == null && m % 4 == 1) { + System.out.println("cast to String[]"); + return new PathRemover((String[])null); + } else if (keyToRemove == null && m % 4 == 2) { + System.out.println("cast to JSONArray"); + return new PathRemover((JSONArray)null); + } else if (keyToRemove == null && m % 4 == 3) { + System.out.println("cast to List"); + return new PathRemover((List)null); + } else if (keyToRemove instanceof String) { + return new PathRemover((String)keyToRemove); + } else if (keyToRemove instanceof String[]) { + return new PathRemover((String[])keyToRemove); + } else if (keyToRemove instanceof JSONArray) { + return new PathRemover((JSONArray)keyToRemove); + } else if (keyToRemove instanceof List) { + return new PathRemover((List)keyToRemove); + } else { + throw new IllegalArgumentException("bad test setup: wrong type of key to remove"); + } + } + +} diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java similarity index 100% rename from json-smart/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/PathReplicatorTest.java diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java similarity index 100% rename from json-smart/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/PathsRetainerTest.java diff --git a/json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java b/json-smart-action/src/test/java/net/minidev/json/test/actions/TreePathTest.java similarity index 100% rename from json-smart/src/test/java/net/minidev/json/test/actions/TreePathTest.java rename to json-smart-action/src/test/java/net/minidev/json/test/actions/TreePathTest.java diff --git a/json-smart/pom.xml b/json-smart/pom.xml index 5e35f2f1..29b23e35 100644 --- a/json-smart/pom.xml +++ b/json-smart/pom.xml @@ -1,112 +1,99 @@ - - - 4.0.0 - net.minidev - json-smart - 2.2.1-b-SNAPSHOT - JSON Small and Fast Parser - + + + net.minidev + minidev-parent + 2.2.1-b-SNAPSHOT + + + 4.0.0 + json-smart + JSON Small and Fast Parser + JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language. - bundle - http://www.minidev.net/ - - Chemouni Uriel - http://www.minidev.net/ - - - - uriel - Uriel Chemouni - uchemouni@gmail.com - GMT+1 - - - - - erav - Eitan Raviv - adoneitan@gmail.com - GMT+2 - - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - All files under Apache 2 - - - - UTF-8 - 1.5 - 1.5 - - - - junit - junit - 4.12 - test - - - net.minidev - accessors-smart - 1.1 - - - - - - - - - - - scm:git:https://github.com/netplex/json-smart-v2.git - scm:git:https://github.com/netplex/json-smart-v2.git - https://github.com/netplex/json-smart-v2 - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - - release-sign-artifacts - - - - performRelease - true - - - - - 2C8DF6EC - - - - - - - + scm:git:https://github.com/netplex/json-smart-v2.git + scm:git:https://github.com/netplex/json-smart-v2.git + https://github.com/netplex/json-smart-v2 + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + release-sign-artifacts + + + + performRelease + true + + + + + 2C8DF6EC + + + + + + + - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - - - attach-javadocs - - jar - - - - - + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + attach-javadocs + + jar + + + + + - - org.apache.maven.plugins - maven-release-plugin - 2.5.2 - - forked-path - -Psonatype-oss-release - false - false - release - deploy - - - - - - - include-sources - - - - / - true - src/main/java - - **/*.java - - - - - - - - - - - org.apache.maven.plugins - maven-source-plugin - 2.4 - - - bind-sources - - jar-no-fork - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - UTF-8 - 1.6 - 1.6 - - **/.svn/* - **/.svn - - - - - - org.apache.maven.plugins - maven-resources-plugin - 2.7 - - UTF-8 - - - - - org.apache.maven.plugins - maven-jar-plugin - 2.6 - - - **/.svn/* - **/.svn - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - - false - - - - - attach-javadocs - - jar - - - - - - org.apache.felix - maven-bundle-plugin - 3.0.0 - true - - - ${project.groupId}.${project.artifactId} - ${project.artifactId} - ${project.version} - - net.minidev.json, net.minidev.json.annotate, net.minidev.json.parser, net.minidev.json.reader, net.minidev.json.writer - - - - - - + + org.apache.maven.plugins + maven-release-plugin + 2.5.2 + + forked-path + -Psonatype-oss-release + false + false + release + deploy + + + + + + + include-sources + + + + / + true + src/main/java + + **/*.java + + + + + + + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + bind-sources + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + UTF-8 + 1.6 + 1.6 + + **/.svn/* + **/.svn + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + UTF-8 + + + + + org.apache.maven.plugins + maven-jar-plugin + 2.6 + + + **/.svn/* + **/.svn + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + + false + + + + + attach-javadocs + + jar + + + + + + org.apache.felix + maven-bundle-plugin + 3.0.0 + true + + + ${project.groupId}.${project.artifactId} + ${project.artifactId} + ${project.version} + + net.minidev.json, net.minidev.json.annotate, net.minidev.json.parser, + net.minidev.json.reader, net.minidev.json.writer + + + + + + \ No newline at end of file diff --git a/parent/pom.xml b/parent/pom.xml index 8b66677b..1a6eb4ed 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.minidev minidev-parent - 2.2.1 + 2.2.1-b-SNAPSHOT Minidev super pom minidev common properties. pom @@ -140,6 +140,7 @@ ../accessors-smart + ../accessors-smart-action ../json-smart @@ -158,12 +159,8 @@ ossrh https://oss.sonatype.org/service/local/staging/deploy/maven2/ - + @@ -232,8 +229,8 @@ maven-release-plugin 2.5.2 - forked-path - -Psonatype-oss-release + forked-path + -Psonatype-oss-release false false release @@ -266,6 +263,11 @@ json-smart ${project.version} + + net.minidev + json-smart-action + ${project.version} + net.minidev accessors-smart @@ -279,7 +281,7 @@ junit junit - 3.8.2 + 4.12 From 9bd4b2869aefabf5c0000cb4ccca88d467d5b5b4 Mon Sep 17 00:00:00 2001 From: UrielCh Date: Sat, 24 Sep 2016 08:16:23 -0700 Subject: [PATCH 17/18] fix pom error --- json-smart/pom.xml | 6 ++++-- parent/pom.xml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/json-smart/pom.xml b/json-smart/pom.xml index 29b23e35..baed6368 100644 --- a/json-smart/pom.xml +++ b/json-smart/pom.xml @@ -250,8 +250,10 @@ ${project.artifactId} ${project.version} - net.minidev.json, net.minidev.json.annotate, net.minidev.json.parser, - net.minidev.json.reader, net.minidev.json.writer + net.minidev.json, net.minidev.json.annotate, + net.minidev.json.parser, + net.minidev.json.reader, + net.minidev.json.writer diff --git a/parent/pom.xml b/parent/pom.xml index 1a6eb4ed..70cff0af 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -140,7 +140,7 @@ ../accessors-smart - ../accessors-smart-action + ../json-smart-action ../json-smart From 1a11a47eb29c91b067225a1e6e9bb2f8b321a792 Mon Sep 17 00:00:00 2001 From: UrielCh Date: Sat, 24 Sep 2016 08:20:49 -0700 Subject: [PATCH 18/18] change version and timeZone in pom --- accessors-smart/pom.xml | 2 +- json-smart-action/pom.xml | 4 ++-- json-smart/pom.xml | 4 ++-- parent/pom.xml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/accessors-smart/pom.xml b/accessors-smart/pom.xml index baf95703..024f51bc 100644 --- a/accessors-smart/pom.xml +++ b/accessors-smart/pom.xml @@ -18,7 +18,7 @@ uriel Uriel Chemouni uchemouni@gmail.com - GMT+1 + GMT-7 diff --git a/json-smart-action/pom.xml b/json-smart-action/pom.xml index 5ac42754..e9ea3a3a 100644 --- a/json-smart-action/pom.xml +++ b/json-smart-action/pom.xml @@ -3,7 +3,7 @@ net.minidev minidev-parent - 2.2.1-b-SNAPSHOT + 2.3-SNAPSHOT 4.0.0 json-smart-action @@ -22,7 +22,7 @@ uriel Uriel Chemouni uchemouni@gmail.com - GMT+1 + GMT-7 diff --git a/json-smart/pom.xml b/json-smart/pom.xml index baed6368..f3f47102 100644 --- a/json-smart/pom.xml +++ b/json-smart/pom.xml @@ -3,7 +3,7 @@ net.minidev minidev-parent - 2.2.1-b-SNAPSHOT + 2.3-SNAPSHOT 4.0.0 @@ -23,7 +23,7 @@ uriel Uriel Chemouni uchemouni@gmail.com - GMT+1 + GMT-7 diff --git a/parent/pom.xml b/parent/pom.xml index 70cff0af..b6f91bea 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.minidev minidev-parent - 2.2.1-b-SNAPSHOT + 2.3-SNAPSHOT Minidev super pom minidev common properties. pom @@ -19,7 +19,7 @@ uriel Uriel Chemouni uchemouni@gmail.com - GMT+1 + GMT-7