Navigation on a complex Java-Objects-graphs

If you want to navigate with a description (language) on a object graph, than you can use the SOJO navigation language. SOJO has three kinds of navigations:

  • Simple: Simple values (getter/setter) from JavaBean properties. (Example: name is correspond to call getName() on a JavaBean with the property name)
  • Iterateable: An Iterateable property are collection or array of objects, that can be accessed by an integer-valued (index, non-negative). (Example: childs[0] is correspond to call getChilds().get(0) on a JavaBean with the property childs. They get the first elemet from the list childs)
  • Map: A Map property is a property with a implementation from the java interface java.util.Map. The elements are composite key-value pairs. You can set and retrieve individual values via a key. (Example: namedChild(key1) is correspond to call getNamedChild().get("key1") on a JavaBean with the property namedChild. They get the elemet for the key key1 from a map).
This three kinds can you combinate with each other. The name for this case is Nested. (Example: childs[0].name is correspond to call ((Node) getChilds().get(0)).getName() on a JavaBean with the property childs, where this property is from type list and contains on the first position a Node - object.

Easy navigation on an complex object graph

Examples for get properties:

// simple example
Node node = new Node("Node");
// result = Node
Object result = PathExecuter.getSimpleProperty(node, "name");

// more complex example (iterateale)
Node node = new Node("Node");
Node childNode1 = new Node("Child-Node-1");
Node childNode2 = new Node("Child-Node-2");
node.getChilds().add(childNode1);
node.getChilds().add(childNode2);

// result = Child-Node-1
Object result = PathExecuter.getNestedProperty(node, "childs[0].name");

Examples for set properties:

// simple example
Node node = new Node("Node");
// name of node is: New-Node
PathExecuter.setSimpleProperty(node, "name", "New-Node");

// more complex example (map)
Node node = new Node("Test-Node");
node.getNamedChilds().put("N1", new Node("N1"));
node.getNamedChilds().put("N2", new Node("N2"));

PathExecuter.setNestedProperty(node, "namedChilds(N3)", new Node("N3"));

// add element to a list, after the last element from the list (no index is set)
node.getChilds().add(new Node("N1-List"));
// is equals to call the PathExecuter
PathExecuter.setNestedProperty(node, "childs[]", new Node("N1-List"));

Combinate get and set properties (this is the basis, for interfaces, where read from source object (and optional convert the value) and write to the target value):

Node node = new Node("Test-Node");
node.getNamedChilds().put("N1", new Node("N1"));
node.getNamedChilds().put("N2", new Node("N2"));
node.getNamedChilds().put("N3", new Node("N3"));

Object node3 = PathExecuter.getNestedProperty(node, "namedChilds(N3)");
PathExecuter.setNestedProperty(node3, "name", "New-N3");

You can observe the "walk" about a object graph. A application for the case is, if you want to record all pathes, where use from the object graph:

Node node = new Node("Test-Node");
ObjectGraphWalker walker = new ObjectGraphWalker();
PathRecordInterceptor interceptor = new PathRecordInterceptor();
walker.addInterceptor(interceptor);

			
walker.walk(node);
Map pathes = interceptor.getAllRecordedPathes();
Iterator iter = pathes.entrySet().iterator();
while (iter.hasNext()) {
	Map.Entry entry = (Entry) iter.next();
	System.out.println(entry.getKey() + ": " + entry.getValue());
}

// the output is (all getter-method, with values):
childs[]: []
namedChilds(): {}
class: test.net.sf.sojo.model.Node
name: Test-Node
parent: null