Experiment with viewing a tree as a list and a map.
This is also a good project to copy as a Kotlin starter following modern JVM build practices.
To build, use ./mvnw clean verify.
Try ./run for a demonstration.
To build as CI would, use ./batect build.
Try ./batect run for a demonstration as CI would.
This project assumes JDK 17. There are no run-time dependencies beyond the Kotlin standard library.
A ListMapTree is a tree data
structure where:
- Each node may have multiple child nodes where nodes are sorted by name
- Each node has properties (an associative array of key-value pairs) where names (keys) are sorted strings
Properties are typed:
- Empty signifying presence but without a value
- Binary data
- Integer data
- Text data
A similar model is the Windows Registry.
(See the tests for examples.)
Create a new tree root (a node) with:
ListMapTree.newRoot(name)
This returns the new root node, a parent node for other child nodes.
depthis how far (how many node traversals) this node lies from the root node. The root node is 0 depth from itselfnameis the node name: all nodes are named, and must be unique among children of a parent, but may be non-unique for nodes with different parent nodes
Create a new child node, and add it to a parent node:
parent.newChild(name)
If a sibling node (a child node of the same parent) is already named name,
throw an IllegalArgumentException.
This returns the new child node when not throwing.
Remove a child node directly or by name from a parent node:
parent.removeChild(node)parent.removeChild(name)
This returns true or false if there were such a child, and removing
succeeded.
Properties with values are typed: Binary Data (arrays of bytes), Integer (signed integer numbers up to 64 bits), Text (string).
Add or change a property of any node with:
node.setProperty(name, value)
This returns the previous property value, or null if the property is new.
Values for properties may be of these types:
EmptyPropertyValue(no constructor [*])BinaryDataPropertyValue(constructed with aByteArrayparameter)IntegerPropertyValue(constructed with aLongparameter)TextPropertyValue(constructed with aStringparameter)
[*] EmptyPropertyValue is special: it has no true value, but holds a
dummy Empty object. Use this when the presence of the property key is all
that you need, and do not need an actual value.
For convience, you may also assign properties with direct values:
node.setProperty(name, Empty))node.setProperty(name, binaryData)node.setProperty(name, number)node.setProperty(name, text)
Remove a property from a node with:
node.removeProperty(name)
As convenience, since child nodes are sorted by name, you may access them with indices:
node[index]yields the nth child node
Similarly for properties:
node[name]yields the value of the property, ornullif missing or emptynode[name] = nullremoves the propertynode[name] = Emptysets the property to the empty valuenode[name] = datasets the property to a binary data valuenode[name] = numbersets the property to an integer valuenode[name] = textsets the property to a text value
Note that these patterns prioritize current node properties over access to children by name (see issue #16).
An example of using chained index accesses:
root[0]["FOO"] // "FOO" property of first child node
child[1]["BAR"] // "BAR" property of second child node of another child node