The code generated by hibernatetool generates an invalid Map Type for generics. There is a Value type parameter, but no Key type parameter.
Hibernate version: hibernate tools CVS version on 20051009
Mapping document:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--
Auto-generated mapping file from
the hibernate.org cfg2hbm engine
-->
<class name="com.praxiseng.reservations.db.Person" table="PERSON" schema="GLMATRA_T2">
<id name="personId" type="integer">
<column name="PERSON_ID" precision="22" scale="0" />
<generator class="native" />
</id>
<map name="seatByFlight"
table="SEAT_ON_FLIGHT">
<key column="PERSON_ID"/>
<index-many-to-many
class="com.praxiseng.reservations.db.Flight" />
<many-to-many class="com.praxiseng.reservations.db.Seat"
column="SEAT_ID"/>
</map>
</class>
</hibernate-mapping>
Generated code:Code:
private Map<com.praxiseng.reservations.db.Seat> seatByFlight;
should be:Code:
private Map<com.praxiseng.reservations.db.Flight, com.praxiseng.reservations.db.Seat> seatByFlight;
Ant target:Code:
<target name="hbm2java">
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="hibernate.path" />
<hibernatetool destdir="generated" >
<configuration
configurationfile="config/hibernate.cfg.xml">
<fileset dir="generated">
<include name="**/*.hbm.xml"/>
</fileset>
</configuration>
<hbm2cfgxml destdir="generated"/>
<hbm2java destdir="generated" generics="true" />
</hibernatetool>
</target>
Generated java property:Code:
private Map<com.praxiseng.reservations.db.Seat, com.praxiseng.reservations.db.Flight> seatByReservation;
I think this is a bug. I went ahead and changed my local copy of Cfg2JavaTool.getRawTypeName() by adding support for Indexed Collections.
Here is my addition...
Code:
if( value instanceof IndexedCollection) {
IndexedCollection ic = (IndexedCollection) value;
String genericParams;
String entityType;
ManyToOne element = (ManyToOne) ic.getElement();
ManyToOne index = (ManyToOne) ic.getIndex();
entityType = element.getReferencedEntityName();
if(index != null) {
String indexType;
indexType = index.getReferencedEntityName();
genericParams = "<" + indexType + ", " + entityType+ ">";
} else {
genericParams = "<" + entityType + ">";
}
return getJavaTypeName(value, preferRawTypeNames) + genericParams;
} else if ( value instanceof Collection ) {
Here is my full version of the method...
Code:
private String getRawTypeName(Property p, boolean useGenerics, boolean preferRawTypeNames) {
Value value = p.getValue();
try {
if ( value instanceof Array ) { // array has a string rep.inside.
Array a = (Array) value;
if ( a.isPrimitiveArray() ) {
return toName( value.getType().getReturnedClass() );
}
else if (a.getElementClassName()!=null){
return a.getElementClassName() + "[]";
} else {
return getJavaTypeName(a.getElement(), preferRawTypeNames) + "[]";
}
}
if ( value instanceof Component ) { // same for component.
return ( (Component) value ).getComponentClassName();
}
if ( useGenerics ) {
if( value instanceof IndexedCollection) {
IndexedCollection ic = (IndexedCollection) value;
String genericParams;
String entityType;
ManyToOne element = (ManyToOne) ic.getElement();
ManyToOne index = (ManyToOne) ic.getIndex();
entityType = element.getReferencedEntityName();
if(index != null) {
String indexType;
indexType = index.getReferencedEntityName();
genericParams = "<" + indexType + ", " + entityType+ ">";
} else {
genericParams = "<" + entityType + ">";
}
return getJavaTypeName(value, preferRawTypeNames) + genericParams;
} else if ( value instanceof Collection ) {
Collection collection = (Collection) value;
String entityType;
if ( collection.isOneToMany() ) {
OneToMany oneToMany = (OneToMany) collection.getElement();
entityType = oneToMany.getAssociatedClass().getClassName();
}
else {
ManyToOne manyToOne = (ManyToOne) collection.getElement();
entityType = manyToOne.getReferencedEntityName();
}
return getJavaTypeName(value, preferRawTypeNames) + "<" + entityType + ">";
}
}
return getJavaTypeName( value, preferRawTypeNames );
}
catch (Exception e) {
//e.printStackTrace();
String msg = "Could not resolve type without exception for " + p + " Value: " + value;
if ( value != null && value.isSimpleValue() ) {
String typename = ( (SimpleValue) value ).getTypeName();
log.warn( msg + ". Falling back to typename: " + typename );
return typename;
}
else {
throw new ExporterException( msg, e );
}
}
}
I don't know if this is the best way to fix it or not as this is the first time I've fished around in the hibernate-tools source.
Thanks,
Geoff
Disclamer: No code in this post came from an actual project from my employer, it was generated just for use as an example.