net.sf.hibernate.tool.class2hbm
Class MapGenerator

java.lang.Object
  extended by net.sf.hibernate.tool.class2hbm.MapGenerator

public class MapGenerator
extends Object

MapGenerator provides a mechanism to produce a Hibernate XML OR-Mapping from compiled classes. It does this using Java reflection to find properties to be persisted in the classes, and using the types of the properties to further guide the reflection.

The usual way to use MapGenerator is to place your compiled classes on the classpath, and start Java in the MapGenerator static main() method. As arguments you can either supply all of the classes to be processed, or the single argument --interact which will provide an interactive prompt/response console. Using this mode you can set the UID property name for each class using the uid=XXX command where XXX is the UID property name. Other command alternatives are simply a fully qualified class name, or the command done which emits the XML and terminates.

MapGenerator will reject classes that are not hibernate perisitable. To be hibernate persistable a class must not be a primitive type, an array, an interface, or a nested class, and it must have a default (zero argument) constructor.

MapGenerator will climb the superclass chain of all added classes attempting to add as many hibernate perisitable superclasses as possible to the same database table. The search stops as soon as a property is found that has a name appearing on the list of candidate UID names, and has type String, Long, or long.

Properties are discovered when there are two methods in the class, a setter and a getter, where the type of the setter's single argument is the same as the return type of the zero argument getter, and the setter returns void. Furthermore, the setter's name must start with the string "set" and either the getter's name starts with "get" or the getter's name starts with "is" and the type of the property is boolean. In either case, the remainder of their names must match. This matching portion is the name of the property, except that the initial character of the property name is made lower case if the second letter is lower case.

The rules for determing the database type of each property are as follows. If the Java type is Hibernate.basic(), then the property is a simple column of that type. For hibernate.type.Type custom types and PersistentEnum a simple column is used as well. If the property type is an array, then a Hibernate array is used, and MapGenerator attempts to reflect on the array element type. If the property has type java.util.List, java.util.Map, or java.util.Set, then the corresponding Hibernate types are used, but MapGenerator cannot further process the insides of these types. If the property's type is any other class, MapGenerator defers the decision on the database representation until all classes have been processed (i.e., until done is typed at the interactive prompt. At this point, if the class was discovered through the superclass search described above, then the property is an association (many-to-one). If the class has any properties, then it is a component. Otherwise it is serializable, or not persistable.

Version:
1.x
Author:
e

Field Summary
protected  Hashtable abstractClasses
          A list of class names which are treated as 'abstract' in that they are not allowed to be root classes.
protected  StringBuffer buf
          the XML we make; this buffer is shared by all string emitters created by this MapGenerator instance
protected  Hashtable cycleBuster
          a cache of emitted components for the current property; Class -> Integer
also necessary to avoid infinite regress by tracking the depth of data recursion
protected  int maxDepth
          how low will you go? the depth of component nesting followed
protected  String[] niceKeys
          candidate UID property names; presence of one of these with a supported type (String, Long, long) will stop the reflect code from chasing the superclass chain any further except to find additional properties (not classes)
protected  Hashtable rClasses
          a cache of seen reflected classes; Class -> ReflectedClass
also necessary to avoid infinite regress
 
Constructor Summary
MapGenerator(String[] className, ClassLoader loader)
          the only MapGenerator constructor
 
Method Summary
 void addClass(String className, boolean verbose)
          add a class to the map and reflect upon it
 void addUID(String uid)
          add a new name to the front of the list of candidate UIDs
protected  Class checkClass(Class clazz, String className, boolean v)
          verify that a class is hibernate-persistable
protected  Class checkComponent(Class clazz, String className, boolean v)
          verify that a class is hibernate-persistable as a component
protected  String columnNameFor(String best)
           
protected  void emitPrefix(int n)
          adds spaces to the front of lines in buf for indentation
 ReflectedClass[] getRoots()
          used by gui
 String getXML()
          after all classes are added
static void main(String[] args)
           
protected  ReflectedProperty makeProperty(String name, Class cls)
          this is the factory to make a ReflectedProperty
using this factory will insure that the property types are inferred consistently
protected  String nextName(String best, Hashtable h)
          used to make unique table and column names
 void reset()
          start over
 void setClassLoader(ClassLoader classLoader)
           
 void setUID(String uid)
          set the list of candidate UIDs to a single name
protected  String tableNameFor(String name)
           
 void writeXML(Writer outputWriter)
           
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

maxDepth

protected int maxDepth
how low will you go? the depth of component nesting followed


niceKeys

protected String[] niceKeys
candidate UID property names; presence of one of these with a supported type (String, Long, long) will stop the reflect code from chasing the superclass chain any further except to find additional properties (not classes)


buf

protected StringBuffer buf
the XML we make; this buffer is shared by all string emitters created by this MapGenerator instance


rClasses

protected Hashtable rClasses
a cache of seen reflected classes; Class -> ReflectedClass
also necessary to avoid infinite regress


abstractClasses

protected Hashtable abstractClasses

A list of class names which are treated as 'abstract' in that they are not allowed to be root classes. Classes added to this list will have their properties (and their superclass properties) mapped to any subclasses extending the base classes listed here. Documentation notes: --abstract= use to add a class which will have its properties persisted only by its subclasses. Multiple --abstract entries can be used, but they must all come before any class names to be mapped. Classes listed by this option do not need to actually be abstract in the Java language sense.

Note that the name abstract is somewhat misleading as abstract classes can otherwise be handled as a top level class by Hibernate.


cycleBuster

protected Hashtable cycleBuster
a cache of emitted components for the current property; Class -> Integer
also necessary to avoid infinite regress by tracking the depth of data recursion

Constructor Detail

MapGenerator

public MapGenerator(String[] className,
                    ClassLoader loader)
the only MapGenerator constructor

Parameters:
className - an array of fully specified class names to add, or null
Method Detail

main

public static void main(String[] args)

writeXML

public void writeXML(Writer outputWriter)

reset

public void reset()
start over


addClass

public void addClass(String className,
                     boolean verbose)
add a class to the map and reflect upon it

Parameters:
className - a fully qualified class name in the class path
verbose - squawk (as a comment into the final XML) if there are problems with this class

setUID

public void setUID(String uid)
set the list of candidate UIDs to a single name

Parameters:
uid - the new candidate UID

addUID

public void addUID(String uid)
add a new name to the front of the list of candidate UIDs

Parameters:
uid - the new candidate UID

getRoots

public ReflectedClass[] getRoots()
used by gui


nextName

protected String nextName(String best,
                          Hashtable h)
used to make unique table and column names

Parameters:
best - is the desired name
h - is the uniqifying hashtable
Returns:
the unique name

tableNameFor

protected String tableNameFor(String name)

columnNameFor

protected String columnNameFor(String best)

emitPrefix

protected void emitPrefix(int n)
adds spaces to the front of lines in buf for indentation

Parameters:
n - indentation level

getXML

public String getXML()
after all classes are added

Returns:
the XML

makeProperty

protected ReflectedProperty makeProperty(String name,
                                         Class cls)
this is the factory to make a ReflectedProperty
using this factory will insure that the property types are inferred consistently

Parameters:
name - the property name
cls - the property class
Returns:
the new ReflectedProperty

checkClass

protected Class checkClass(Class clazz,
                           String className,
                           boolean v)
verify that a class is hibernate-persistable

Parameters:
clazz - the class to ckeck
className - the name of the class for error reporting
v - verbose - should be true for supplied classes, but false for chased superclasses
Returns:
the class clazz if it is hibernate-persistable, else null

checkComponent

protected Class checkComponent(Class clazz,
                               String className,
                               boolean v)
verify that a class is hibernate-persistable as a component

Parameters:
clazz - the class to ckeck
className - the name of the class for error reporting
v - verbose - should probably always be true, but can be false to ignore the property's status
Returns:
the class clazz if it is hibernate-persistable as a component, else null

setClassLoader

public void setClassLoader(ClassLoader classLoader)