Common operation of complex Java-Objects-graphs

In the first section you can see examples, where you can use SOJO for a better/easyer operate on object graphs. The aim is, to get operations, how you know from associate with simple Java objects.

Copy/clone a complex object graph

This subsection describe, how you can copy/clone complex object graph. Both graph have your own instance from the objects, but the instances have the same values. Example:

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);
		
Node nodeCopy = (Node) new ObjectUtil().copy(node);

The Node node and nodeCopy are equals from your values, but not the same objects. You can change values from Node node and can back (undo) to the original values, if you want reject your changes.

With copy from object graphs, you can manage different version (object history) from one object graph.

Compare complex object graph

If you want to control the copy operation from the section before, than can you use the equals method.

...
// equals is true
boolean equals = new ObjectUtil().equals(node, nodeCopy);

childNode2.setName("Rename-Child-Node-2");
// equals is false
equals = new ObjectUtil().equals(node, nodeCopy);

The complement to the equals method, the hashCode - method.

public int hashCode() {
  return new ObjectUtil().hashCode(this);
}

// or a more performance variant
...
private ObjectUtil objectUtil = new ObjectUtil();
private Integer hashCode = null;

public int hashCode() {
  if (hashCode == null) {
  	hashCode = new Integer(objectUtil.hashCode(this));
  }
  return hashCode.intValue();
}

If you want to get more information by compare object graph, than use the compare method. This method find the first differents and than is the search breaking.

Node node1 = new Node("Test-Node");
Node node2 = new Node("Test-Node");
ObjectUtil objectUtil = new ObjectUtil();
CompareResult result = objectUtil.compare(node1, node2);
// result is null, both nodes are equals

node2 = new Node("Test-Node-OTHER");
result = objectUtil.compare(node1, node2);
// result is:
// result.differentPath = "name"
// result.differentValue1 = "Test-Node"
// result.differentValue2 = "Test-Node-OTHER"

For find all differents by comparing object graphs, use the compareAll method. This method find all differents.

Car car1 = new Car("BMW");
car1.setDescription("my car");
car1.setProperties(new Properties());
car1.getProperties().put("key", "value");
		
Car car2 = new Car("BMW");
car2.setDescription("your car");
car2.setProperties(new Properties());
car2.getProperties().put("key", "other-value");

CompareResult result[] = new ObjectUtil().compareAll(car1, car2);
// result is:
// path: description - first value: my car - second value: your car
// path: properties(key) - first value: value - second value: other-value

Walk over (to traverse) object graph

If you want to traverse a object graph, than can use the helper ObjectGraphWalker. By registration from a WalkerInterceptor can you get information about the visited object (path to this object, number of recursion and so on).

Car car = new Car("Ferrari");
ObjectGraphWalker walker = new ObjectGraphWalker();
PathRecordWalkerInterceptor interceptor = new PathRecordWalkerInterceptor();
walker.addInterceptor(interceptor);
		
walker.walk(car);
Map visitedPathes = interceptor.getAllRecordedPathes();

// test the path
Object carName = PathExecuter.getNestedProperty(car, "name");
assertEquals(carName, visitedPathes.get("name"));

You can write your own WalkerInterceptor:

								
public class MyWalkerInterceptor implements WalkerInterceptor {

	public void startWalk(Object startObject) { 
		System.out.println("Start the walking.");
	}
	
	public void endWalk() { 
		System.out.println("\nWalking is done.");
	}


	public boolean visitElement(Object key, int index, Object value, int type, String path, int numberOfRecursion) {
		if (type == Constants.TYPE_SIMPLE || type == Constants.TYPE_NULL) {
			System.out.print(path + ": " + value + ", ");	
		}
		return false;
	}

	public void visitIterateableElement(Object value, int type, String path, int typeBeginOrEnd) {

		if (typeBeginOrEnd == Constants.ITERATOR_BEGIN) {
			if (type == Constants.TYPE_ITERATEABLE) {
				System.out.print("[");
			} else if (type == Constants.TYPE_MAP) {
				System.out.print("(");
			}
		} else if (typeBeginOrEnd == Constants.ITERATOR_END) {
			if (type == Constants.TYPE_ITERATEABLE) {
				System.out.print("]");
			} else if (type == Constants.TYPE_MAP) {
				System.out.print(")");
			}
		}
		
	}


}

The type can you find in the interface net.sf.sojo.Constants. Possible values are: TYPE_SIMPLE, TYPE_ITERATEABLE, TYPE_MAP, TYPE_NULL.