Class JSNode
- Direct Known Subclasses:
JSArray
Inversion encourages working with JSON data structures abstractly instead of transcoding them into a concrete Java object model. So JSNode and JSArray were designed to make it as easy as possible to work with JSON in its "native form."
JSNode and JSArray are a one stop shop for:
- Parsing and printing JSON
- Finding elements of a document with JSONPath and JSONPointer
- Diff and patching with JSONPatch
Property name case is preserved but considered case insensitive when accessing a property by name.
Property iteration or is preserved based on insertion order.
It is possible to create a document with a child JSNode appearing multiple times in the document including circular reference loops. When printing a document, if a JSNode has previously been printed AND it has an 'href' property, instead of erroring, the printer will write an '@link' property pointing to the previously printed href. If the JSNode does not have an 'href' an error will be thrown.
Under the covers this Jackson is used as the json parser.
- See Also:
-
Nested Class Summary
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionasArray()Similar to #asList() but instead of returning a List, it returns a this JSNode as the only item in a JSArray.asList()Returns this object as the only element in a list.asMap()Returns this object as the only element in a Listvoidclear()Removes all propertiesbooleancontainsKey(Object name) booleancontainsValue(Object value) Checks all property values for equality tovaluecopy()Makes a deep copy of this JSNode by stringifying/parsing.entrySet()Convenience overloading offindAll(String, int)that returns the first item foundConvenience overloading offindAll(String, int)A heroically permissive finder supporting JSON Pointer, JSONPath and a simple 'dot and wildcard' type of system like so: 'propName.childPropName.*.skippedGenerationPropsName.4.fifthArrayNodeChildPropsName.**.recursivelyFoundPropsName'.findAllNodes(String pathExpression) Convenience overloading offindAll(String, int)Convenience overloading offind(String)booleanfindBoolean(String pathExpression) Convenience overloading offind(String)doublefindDouble(String pathExpression) Convenience overloading offind(String)intConvenience overloading offind(String)longConvenience overloading offind(String)Convenience overloading offind(String)findString(String pathExpression) Convenience overloading offind(String)Convenience overloading ofget(Object)booleangetBoolean(String name) Convenience overloading ofget(Object)doubleConvenience overloading ofget(Object)intConvenience overloading ofget(Object)longConvenience overloading ofget(Object)Convenience overloading ofget(Object)Convenience overloading ofget(Object)booleanhasProperty(String name) booleanisArray()Easy alternative to 'instanceof' to differentiate JSNode from JSArray (which subclasses JSNode).booleanisEmpty()keySet()static ObjectTurns a JSON string in to JSNode (maps), JSArray (lists), String numbers and booleans.static JSArrayparseJsonArray(String json) Utility overloading ofparseJson(String)to cast the return as a JSArraystatic JSNodeparseJsonNode(String json) Utility overloading ofparseJson(String)to cast the return as a JSNodevoidvoidVanity method to make sure the attributes prints out firstRemoves all properties withnames.intsize()voidsortKeys()Changes the property name iteration order from insertion order to alphabetic order.stream()Convenience method that calls asList().stream().toString()toString(boolean pretty) Prints the JSNode with properties written out in their original case.toString(boolean pretty, boolean lowercasePropertyNames) Prints the JSNodevalues()Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, waitMethods inherited from interface java.util.Map
compute, computeIfAbsent, computeIfPresent, equals, forEach, getOrDefault, hashCode, merge, putIfAbsent, remove, replace, replace, replaceAll
-
Constructor Details
-
JSNode
public JSNode()Creates an empty JSNode. -
JSNode
Creates a JSNode withnameValuePairsas the initial properties.The first and every other element in
nameValuePairsshould be a string.- Parameters:
nameValuePairs- the name value pairs to add- See Also:
-
JSNode
Creates a JSNode withnameValuePairsas the initial properties.- Parameters:
nameValuePairs- the name value pairs to add- See Also:
-
-
Method Details
-
parseJson
Turns a JSON string in to JSNode (maps), JSArray (lists), String numbers and booleans.Jackson is the underlying parser
- Parameters:
json- the json string to parse- Returns:
- a String, number, boolean, JSNode or JSArray
-
parseJsonNode
Utility overloading ofparseJson(String)to cast the return as a JSNode- Parameters:
json- the json string to parse- Returns:
- the result of parsing the json document cast to a JSNode
- Throws:
ClassCastException- if the result of parsing is not a JSNode
-
parseJsonArray
Utility overloading ofparseJson(String)to cast the return as a JSArray- Parameters:
json- a json string containing an as the root element- Returns:
- the result of parsing the json document cast to a JSArray
- Throws:
ClassCastException- if the result of parsing is not a JSArray
-
findAll
A heroically permissive finder supporting JSON Pointer, JSONPath and a simple 'dot and wildcard' type of system like so: 'propName.childPropName.*.skippedGenerationPropsName.4.fifthArrayNodeChildPropsName.**.recursivelyFoundPropsName'.All forms are internally converted into a 'master' form before processing. This master simply uses '.' to separate property names and array indexes and uses uses '*' to represent a single level wildcard and '**' to represent a recursive wildcard. For example:
- 'myProp' finds 'myProp' in this node.
- 'myProp.childProp' finds 'childProp' on 'myProp'
- 'myArrayProp.2.*' finds all properties of the third element of the 'myArrayProp'
- '*.myProp' finds 'myProp' in any of the children of this node.
- '**.myProp' finds 'myProp' anywhere in my descendents.
- '**.myProp.*.value' finds 'value' as a grandchild anywhere under me.
- '**.*' returns every element of the document.
- '**.5' gets the 6th element of every array.
- '**.book[?(@.isbn)]' finds all books with an isbn
- '**.[?(@.author = 'Herman Melville')]' finds all book with author 'Herman Melville'
Arrays indexes are treated just like property names but with integer names. For example "myObject.4.nextProperty" finds "nextProperty" on the 5th element in the "myObject" array.
JSON Pointer is the least expressive supported form and uses '/' characters to separate properties. To support JSON Pointer, we simply replace all '/' characters for "." characters before processing.
JSON Path is more like XML XPath but uses '.' instead of '/' to separate properties. Technically JSON Path statements are supposed to start with '$.' but that is optional here. The best part about JSON Path is the query filters that let you conditionally select elements.
Below is the implementation status of various JSON Path features:
- SUPPORTED $.store.book[*].author //the authors of all books in the store
- SUPPORTED $..author //all authors
- SUPPORTED $.store..price //the prices of all books
- SUPPORTED $..book[2] //the third book
- SUPPORTED $..book[?(@.price@lt;10)] //all books priced @lt; 10
- SUPPORTED $..[?(@.price@lt;10)] //find any node with a price property
- SUPPORTED $..[?(@.*.price@lt;10)] //find the parent of any node with a price property
- SUPPORTED $..book[?(@.author = 'Herman Melville')] //all books where 'Herman Melville' is the author
- SUPPORTED $..* //all members of JSON structure.
- SUPPORTED $..book[(@.length-1)] //the last book in order
- SUPPORTED $..book[-1:] //the last book in order
- SUPPORTED $..book[0,1] //the first two books
- SUPPORTED $..book[:2] //the first two books
- SUPPORTED $..book[?(@.isbn)] //find all books with an isbn property
- SUPPORTED $..[?(@.isbn)] //find any node with an isbn property
- SUPPORTED $..[?(@.*.isbn)] //find the parent of any node with an isbn property
- SUPPORTED $..[?(@.*.*.isbn)] //find the grandparent of any node with an isbn property
The JSON Path following boolean comparison operators are supported:
- =
- @gt;
- @lt;
- @gt;=
- @lt;=
- !=
JsonPath bracket-notation such as "$['store']['book'][0]['title']" is currently not supported.
- Parameters:
pathExpression- defines the properties to findqty- the maximum number of results- Returns:
- an array of found values
- See Also:
-
diff
-
patch
-
get
-
getNode
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the value of property
namecast to a JSNode if exists else null - Throws:
ClassCastException- if the object found is not a JSNode- See Also:
-
getArray
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the value of property
namecast to a JSArray if exists else null - Throws:
ClassCastException- if the object found is not a JSArray- See Also:
-
getString
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the stringified value of property
nameif it exists else null - See Also:
-
getInt
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the value of property
namestringified and parsed as an int if it exists else -1 - See Also:
-
getLong
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the value of property
namestringified and parsed as long if it exists else -1 - See Also:
-
getDouble
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the value of property
namestringified and parsed as a double if it exists else -1 - See Also:
-
getBoolean
Convenience overloading ofget(Object)- Parameters:
name- the case insensitive property name to retrieve.- Returns:
- the value of property
namestringified and parsed as a boolean if it exists else false - See Also:
-
findNode
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the nodes to find- Returns:
- the first value found at
pathExpressioncast as a JSNode if exists else null - Throws:
ClassCastException- if the object found is not a JSNode- See Also:
-
findArray
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first value found at
pathExpressioncast as a JSArray if exists else null - Throws:
ClassCastException- if the object found is not a JSArray- See Also:
-
findString
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first value found at
pathExpressionstringified if exists else null - See Also:
-
findInt
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first value found at
pathExpressionstringified and parsed as an int if exists else -1 - See Also:
-
findLong
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first value found at
pathExpressionstringified and parsed as a long if exists else -1 - See Also:
-
findDouble
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first value found at
pathExpressionstringified and parsed as a double if exists else -1 - See Also:
-
findBoolean
Convenience overloading offind(String)- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first value found at
pathExpressionstringified and parsed as a boolean if exists else false - See Also:
-
find
Convenience overloading offindAll(String, int)that returns the first item found- Parameters:
pathExpression- specifies the properties to find- Returns:
- the first item found at
pathExpression - See Also:
-
findAll
Convenience overloading offindAll(String, int)- Parameters:
pathExpression- specifies the properties to find- Returns:
- all items found for
pathExpression - See Also:
-
findAllNodes
Convenience overloading offindAll(String, int)- Parameters:
pathExpression- specifies the properties to find- Returns:
- all items found for
pathExpressioncast as a List - See Also:
-
put
-
putAll
-
putFirst
Vanity method to make sure the attributes prints out first- Parameters:
name- the property namevalue- the property value- Returns:
- the previous value of the property if it exists or null
-
with
-
containsKey
- Specified by:
containsKeyin interfaceMap<String,Object>
-
remove
-
removeAll
Removes all properties withnames.- Parameters:
names- the keys to remove- Returns:
- the first non null value for
names
-
keySet
-
hasProperty
-
asMap
-
copy
Makes a deep copy of this JSNode by stringifying/parsing.- Returns:
- a deep copy of this node.
-
sortKeys
public void sortKeys()Changes the property name iteration order from insertion order to alphabetic order. -
isArray
public boolean isArray()Easy alternative to 'instanceof' to differentiate JSNode from JSArray (which subclasses JSNode).- Returns:
- true if this class is a subclass of JSArray.
- See Also:
-
toString
-
toString
Prints the JSNode with properties written out in their original case.- Parameters:
pretty- should spaces and carriage returns be added to the doc for readability- Returns:
- json string, with properties written out in their original case optional pretty printed.
-
toString
Prints the JSNode- Parameters:
pretty- should spaces and carriage returns be added to the doc for readabilitylowercasePropertyNames- when true all property names are printed in lower case instead of their original case- Returns:
- a json string
-
size
public int size() -
isEmpty
public boolean isEmpty() -
containsValue
Checks all property values for equality tovalue- Specified by:
containsValuein interfaceMap<String,Object> - Returns:
- true if any property values are equal to
value
-
clear
public void clear()Removes all properties -
values
-
entrySet
-
asList
Returns this object as the only element in a list.JSArray overrides this method to return all of its elements in a list.
This method is designed to make it super easy to iterate over all property values or array elements without having to cast or consider differences between JSNode and JSArray.
For example:
JSNode node = response.getJson();//don't know if this is a JSNode or JSArray for(Object value : node.asList()) { //do something; }- Returns:
- A List with this node as the only value.
- See Also:
-
asNodeList
Returns this object as the only element in a ListJSArray overrides this method to return all of its elements in a list.
This method is designed to make it super easy to iterate over all property values or array elements without having to cast or consider differences between JSNode and JSArray.
For example:
JSNode node = response.getJson();//don't know if this is a JSNode or JSArray for(JSNode child : node.asList()) { System.out.println("found items with price: " + child.find("**.item.price")); }- Returns:
- A List with this node as the only value.
- See Also:
-
asArray
Similar to #asList() but instead of returning a List, it returns a this JSNode as the only item in a JSArray.JSArray overrides this method to simply return 'this'.
- Returns:
- a JSArray with 'this' as the only element.
- See Also:
-
stream
Convenience method that calls asList().stream().- Returns:
- asList().stream()
-
streamAll
- Returns:
- a stream of findAll(**.*) plus "this"
-