This section describe the core SOJO API. The main aim from this framework is, to provide a "pluggable" basis to integrate different kind of conversions (also your own implementations). With this infrastructure can solve problems, where POJOs are not supported or are not the best decision.

SOJO design description?

The possible property types, that are supported by a JavaBean (and SOJO) can be broken into three groups:
  • Simple: Simple properties are such as int, long, double (primitive data types) or a simple object (such as a java.lang.String, java.lang.Long, java.uilt.Date and so on). The class net.sf.sojo.core.reflect.ReflectionHelper is to be responsible for define classes, which are simple (can test it with method isSimpleType). With the method addSimpleType can add more types at runtime.
  • Iterateable: An Iterateable property stores a collection of objects that can be accessed by an integer-valued (index, non-negative) or by an iterator. Interfaces for this category are java.util.List, java.util.Set or the super interface java.util.Collection. An Iterateable property can also be an Array.
  • 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.
The outcome of this categories of JavaBeans-properties are kinds of conversion. The main classes for conversions are the Java interface net.sf.sojo.core.Conversion respectively the abstract implementation net.sf.sojo.core.AbstractConversion. The first extensions are net.sf.sojo.core.SimpleConversion and net.sf.sojo.core.ConversionIterator. The net.sf.sojo.core.ConversionIterator is splitting in net.sf.sojo.core.ComplexConversion and net.sf.sojo.core.IterateableConversion.

For different kind of properties (category) exist different kind of strategies for conversions:
  • SimpleConversion: Convert a Simple to a simple type. A example is the transformation from String to Long. For this problem you can use the:net.sf.sojo.core.conversion.Simple2SimpleConversion
  • ConversionIterator: is splitting in sub classes:
    • IterateableConversion: This category is equivalent to JavaBean category Iterateable. Conversions implementations are: net.sf.sojo.core.conversion.Iterateable2IterateableConversion or net.sf.sojo.core.conversion.IterateableMap2MapConversion or net.sf.sojo.core.conversion.IterateableMap2BeanConversion
    • ComplexConversion: This category is equivalent to JavaBean category Map. Conversions implementations are: net.sf.sojo..coreconversion.ComplexBean2MapConversion

How can start with SOJO?

This examples are an initiation to the SOJO API and they explain how this framework can use:

  1. Create a instance from the Converter class
  2. add conversions to the Converter instance
  3. call the convert method to transform source object to the target object
An other example is to invoke the convert method two of times. So you can copy/clone every object. This means, that the first convert method make the object simple and the second call produced again a complex object with the same values, how the original source object.

The Converter find cycles in the object graph and create after the copy the same number of objects.

This little examples shows a extract from the SOJO-API and illustrate the entrance in this framework. This is a simple example, that shown, how can convert Strings to other types (e.g.: if values are come from (property, XML) file).

 Converter converter = new Converter();
 converter.addConversion(new Simple2SimpleConversion(String.class, Long.class));
 String s = "57";
 Object result = converter.convert(s);
 assertEquals(Long.class, result.getClass());
 assertEquals(new Long("57"), result);		

The second example illustrate a customer with your adresses that is converted in a simplified representation. This means, objects are converted to maps. The benefit from this idea is, with this representation (convert and convert back = copy or clone) can solve problems there are described in the previous subsection POJOs versus SOJO.

example for a conversion for JavaBeans

The figure show the transformation from JavaBeans to a simplified representation. On the left side you can find the classes customer with a relation (one to many) to adress and on the right side you find a instance from a converted customer instance to a java.util.Map. The same is with adress.

 Converter converter = new Converter(); 
 converter.addConversion(new ComplexBean2MapConversion());
 converter.addConversion(new Iterateable2IterateableConversion());
 Customer customer = new Customer();
 customer.getAdresses().add(new Adress("London")); 
 customer.getAdresses().add(new Adress("Berlin")); 

 Object result = converter.convert(customer);
 assertTrue(result instanceof Map);
 Map map = (Map) result;
 assertEquals(Customer.class.getName(), map.get("class"));
 assertEquals("Paul", map.get("firstName"));
 assertTrue(((List) map.get("adresses")).get(0)  instanceof Map);

In the second example you can see one advantage. The navigation is simplified. It exist three types:

  • gets on a map with a simple result type map.get("name")
  • gets on a map with a result as List - map.get("adresses")
  • gets on a map with a result as Map - ((List) map.get("adresses")).get(0) => a simple navigatin path can be: adresses[0].postal
Thats are all possibilities!

=> This is simplification! This is SOJO!

Convert one structure to other

This simple Example convert String in a Double value (It is usefull, if the value (String) come from a property-file and want to set to a JavaBean.):

 Converter converter = new Converter();
 converter.addConversion(new Simple2SimpleConversion(String.class, Double.class));
 String s = "57.3";
 Object result = converter.convert(s);
 assertEquals(Double.class, result.getClass());
 assertEquals(new Double("57.3"), result);		

This Example convert every Bean in a Map, where the property are the keys and the property-values are the map-values:

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"));

Converter converter = new Converter();
converter.addConversion(new IterateableMap2MapConversion());
converter.addConversion(new Iterateable2IterateableConversion());
converter.addConversion(new ComplexBean2MapConversion());

Object simple = converter.convert(node);
Map map = (Map) simple;
System.out.println("Name: " + map.get("name"));
// print: Name: Test-Node

// and back to the Node-Object
Node nodeCopy = (Node) converter.convert(simple);

The same result, but a easy call is this variante:

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"));

ObjectUtil objectUtil = new ObjectUtil();
Object simple = objectUtil.makeSimple(node);

// and back to the Node-Object
Node nodeCopy = (Node) objectUtil.makeComplex(simple);

Switch from method access to field access

The default access to JavaBean properties by SOJO is per method (Setter and Getter method access). In some cases it doesn't work. An example for this case javax.swing.tree.DefaultMutableTreeNode. This class is not a correct JavaBean. You can add a child node with the add method and not with a setter method.

The solution is a switch from method access to a field access. The switch is activate with register the class:

// first parameter is the class, second parameter is a possible filter
ReflectionFieldHelper.addAllFields2MapByClass(DefaultMutableTreeNode.class, null);

// the inverse switch is the remove class