HIBERNATE JBoss.org
 |  Register  | 
     
News 
About 
   Feature List 
   Road Map 
Documentation 
   Related Projects 
   External Documentation 
Download 
Forum & Mailinglists 
Support & Training 
JIRA Issue Tracking
Wiki Community Area


Hibernate Public Training Courses


Get Hibernate in Action eBook!


JavaWorld 2003 Finalist


Jolt Award 2004 Winner
      
Documentation > Community Area > UserType for Polymorphic Associations

UserType for Polymorphic Associations

The default mapping mechanism for <any> mapping is the class name. This custom type allows for creating integer values for each class, and mapping the classes onto the integer values. Thus the table needs to have a integer column and a column corresponding to the primary key of the other table.

Using this class requires creating a derived class as suggested below.

Sample mapping will be as follows :

Scenario

An invoice table stores a reference to a Customer. Customer is an abstract base class and has two derived classes ExternalCustomer and InternalCustomer. Table-per-concreteclass mapping is used. Invoice table has two columns for mapping the customer - customerType and customerId. CustomerType == 1 implies InternalCustomer, CustomerType == 2 implies ExternalCustomer. Invoice class needs to support a method called getCustomer()

<!-- Mapping snippet in Invoice table --> 
<any name="customer" id-type="long" meta-type="com.example.hibernate.customtype.CustomerTypeMapper"> 
  <column name="customerType"/> 
  <column name="customerId"/> 
</any>

Sample Class (to be created by End User )

public class CustomerTypeMapper extends ClassToIntegerMapper 
{ 
    static public final Integer INTERNAL_CUSTOMER = new Integer(1); 
    static public final Integer EXTERNAL_CUSTOMER = new Integer(2); 

    static final private ClassToIntValue[] mappings = 
    { 
        new ClassToIntValue(INTERNAL_CUSTOMER, InternalCustomer.class), 
        new ClassToIntValue(EXTERNAL_CUSTOMER, ExternalCustomer.class) 
    }; 

    public ClassToIntValue[] getMappings() 
    { 
        return mappings; 
    } 
}

Utility class used by the Custom Type

class ClassToIntValue 
{ 
    private Integer intVal; 
    private Class clazz; 

    public ClassToIntValue(Integer intVal, Class clazz) 
    { 
        this.intVal = intVal; 
        this.clazz = clazz; 
    } 

    public Integer getIntVal() 
    { 
        return intVal; 
    } 

    public Class getClazz() 
    { 
        return clazz; 
    } 
}

The Custom Type itself

package com.example.hibernate.customtype; 

import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Types; 

import net.sf.hibernate.Hibernate; 
import net.sf.hibernate.HibernateException; 
import net.sf.hibernate.UserType; 

/** 
 * @author Dhananjay Nene 
 */ 
abstract public class ClassToIntegerMapper implements UserType 
{ 
    static final private int[] TYPES = {Types.INTEGER }; 

    abstract public ClassToIntValue[] getMappings(); 

    public int[] sqlTypes() 
    { 
        return TYPES; 
    } 

    public Class returnedClass() 
    { 
        return java.lang.Class.class; 
    } 

    public boolean equals(Object arg0, Object arg1) throws HibernateException 
    { 
        if (arg0 == arg1) return true; 
        if ((arg0 == null) || (arg1 == null)) return false; 
        return ((java.lang.Class) arg0).equals((java.lang.Class) arg1); 
    } 

    public Object nullSafeGet(ResultSet rs, String[] names, Object owner) 
        throws HibernateException, SQLException 
    { 
        Integer result = (Integer) Hibernate.INTEGER.nullSafeGet(rs,names[0]); 
        if(result == null) 
        { 
            return null; 
        } 
        ClassToIntValue[] mappings = getMappings(); 
        for(int i = 0 ; i < mappings.length ; i++) 
        { 
            if (result.equals(mappings[i].getIntVal())) 
            { 
                return mappings[i].getClazz(); 
            } 
        } 
        return null; 
    } 

    public void nullSafeSet(PreparedStatement stmt, Object value, int index) 
        throws HibernateException, SQLException 
    { 
        java.lang.Class clazz = (java.lang.Class) value; 
        if (clazz == null) 
        { 
            Hibernate.INTEGER.nullSafeSet(stmt,null,index); 
            return; 
        } 
        Integer intval = null; 
        ClassToIntValue[] mappings = getMappings(); 
        for(int i = 0 ; i < mappings.length ; i++) 
        { 
            if (clazz.equals(mappings[i].getClazz())) 
            { 
                intval = mappings[i].getIntVal(); 
            } 
        } 
        Hibernate.INTEGER.nullSafeSet(stmt,intval,index); 
    } 

    public Object deepCopy(Object arg0) throws HibernateException 
    { 
        if (arg0 == null) return null; 
        Class clazz = (Class)arg0; 
        Class newClazz = (Class) Hibernate.CLASS.deepCopy(clazz); 
        return newClazz; 
    } 

    public boolean isMutable() 
    { 
        return false; 
    } 

}
      

coWiki