* @param fieldName The name of the field for which to create the node
* @return the top-level {@link InfoNode} for the object
*/
public final InfoNode createNode( final Class< ? > containingClass, final Object object, final String fieldName )
{
InfoNode node;
if( object == null )
{
return InfoNode.createLeafNode( fieldName, null, fieldName, Object.class );
}
// create the InfoNode object (we first have to determine the node type, down the road, we'll check the
// factories for registered node info node builders for the Class< ? > of the object)
final Class< ? > clazz = object.getClass();
// construct the node. There are several cases to consider:
// 0. the field is annotated with a specified node builder in mind
// 1. the object is intended to be a leaf node: create a leaf InfoNode object
// with the appropriately populated values, and we're done.
// 2. the object is of a special type: use the appropriate node factory
// to construct the appropriate node
// 3. neither of the first two conditions are met: simply call the addNodes(...)
// method recursively to construct the nodes.
// 4. the object is an array, and the array class hasn't been specified in the node
// builder map, then we must treat it as a generic array.
// the first two cases are handled by the info node builders in the info node builders map. even
// the leaf node info node builders may need to be overridden. the third case is handled
// by the compound node
if( containsAnnotatedNodeBuilder( containingClass, fieldName ) )
{
final NodeBuilder builder = getAnnotatedNodeBuilder( containingClass, fieldName );
try
{
node = builder.createInfoNode( containingClass, object, fieldName );
}
catch( ReflectiveOperationException e )
{
final StringBuilder message = new StringBuilder();
message.append( "Node Builder failed to create InfoNode:" ).append( Constants.NEW_LINE );
message.append( " Builder: " ).append( builder.getClass().getName() ).append( Constants.NEW_LINE );
message.append( " Containing Class Name: " ).append( containingClass.getName() ).append( Constants.NEW_LINE );
message.append( " Object: " ).append( clazz.getName() ).append( Constants.NEW_LINE );
message.append( " Field Name: " ).append( fieldName ).append( Constants.NEW_LINE );
LOGGER.error( message.toString() );
throw new IllegalStateException( message.toString(), e );
}
}
else if( containsNodeBuilder( clazz ) )
{
final NodeBuilder builder = getNodeBuilder( clazz );
try
{
// if the containing class is null, then this is a root object and we
// must use the root object version of the createInfoNode method
if( containingClass == null )
{
node = builder.createInfoNode( object, fieldName );
}
else
{
node = builder.createInfoNode( containingClass, object, fieldName );
}
}
catch( ReflectiveOperationException e )
{
final StringBuilder message = new StringBuilder();
message.append( "Node Builder failed to create InfoNode:" ).append( Constants.NEW_LINE );
message.append( " Builder: " ).append( builder.getClass().getName() ).append( Constants.NEW_LINE );
message.append( " Containing Class Name: " ).append( containingClass == null ? "[null]" : containingClass.getName() ).append( Constants.NEW_LINE );
message.append( " Object: " ).append( clazz.getName() ).append( Constants.NEW_LINE );
message.append( " Field Name: " ).append( fieldName ).append( Constants.NEW_LINE );
LOGGER.error( message.toString() );
throw new IllegalStateException( message.toString(), e );
}
}
else if( clazz.isArray() )
{
try
{
node = genaralArrayNodeBuilder.createInfoNode( containingClass, object, fieldName );
}
catch( ReflectiveOperationException e )
{
final StringBuilder message = new StringBuilder();
message.append( "Default Array Node Builder failed to create InfoNode:" ).append( Constants.NEW_LINE );
message.append( " Builder: " ).append( genaralArrayNodeBuilder.getClass().getName() ).append( Constants.NEW_LINE );
message.append( " Containing Class Name: " ).append( containingClass.getName() ).append( Constants.NEW_LINE );
message.append( " Object: " ).append( clazz.getName() ).append( Constants.NEW_LINE );
message.append( " Field Name: " ).append( fieldName ).append( Constants.NEW_LINE );
LOGGER.error( message.toString() );
throw new IllegalStateException( message.toString(), e );
}
}
else
{
// create a new compound node to holds this, since it isn't a leaf node, and
// call (recursively) the addNodes(...) method to add the nodes representing the
// fields of this object to the newly created compound node.
final InfoNode compoundNode = InfoNode.createCompoundNode( fieldName, fieldName, clazz );
node = addNodes( compoundNode, object );
}
// then call addNodes(...) with the newly created node
return node;