[ http://issues.apache.org/jira/browse/IBATIS-332?page=comments#action_12429165 ] Jay Blanton commented on IBATIS-332: ------------------------------------
If possible...I would actually like to see both the jdbcType and the javaType accessible on setParameter method and the getResults methods. As I stated in this post: http://www.nabble.com/jdbcType-javaType-accessibility-in-TypeHandler-tf2130612.html When it comes to one handler that handles one Java Type, but multiple jdbcTypes...we need accessibility to the jdbcType to know what PreparedStatement setXXX method to call and what ResultSet/CallableStatement getXXX to call. Also, in the issue I previously stated we could call the ResultSet/CallableStatement getXXX and cast the result to the specific implementation...in order to define a Superclass Type Handler that can be defined globally to handle all specific instances of that Superclass. > Exposing javaType (resultMap/parameterMap) attribute in TypeHandler methods > for Superclass/Subclass handlers. > ------------------------------------------------------------------------------------------------------------- > > Key: IBATIS-332 > URL: http://issues.apache.org/jira/browse/IBATIS-332 > Project: iBatis for Java > Issue Type: Improvement > Components: SQL Maps > Affects Versions: 2.1.7 > Environment: WebLogic 8.1.5, Oracle 9i, Solaris > Reporter: Jay Blanton > > This improvement is inregards to TypeHandler and its usage with > Superclasses/Subclasses. Currently we have an Abstract object > (TypeSafeEnumeration) that users will extend to create their own specific > implementations of our TypeSafeEnumeration. When they want to map this data > type in iBatis, they have to create a specific handler for each > implementation of the TypeSafeEnumeration. What we would like to accomplish > is to create a single handler for the superclass. But in order to do > this...methods like the getResult in the TypeHandler interface would need to > know how to take a VARCHAR from the database and create the specific > implementation of that superclass. This information is not available to > getResult (but not needed in the setParameter), so therefore a handler must > be created specific to each implementation. I would like to register a > superclass with a global typeHandler in my sqlMapConfig that can handle the > conversion for each specific implementation of that superclass, by utilizing > the javaType (for example). > So a superclass could be registered as the the global javaType with a > superclass based TypeHandler. Then each resultMap/parameterMap could defined > the specific implementation in the javaType and the TypeHandler could use > that resultMap/parameterMap javaType to instantiate the specific version of > that superclass. > I have included below the TO that is getting mapped, and the Superclass > (Abstract) that needs the TypeHandler, and two specific implementations of > that TypeHandler: > TO: > public class ContactTO { > > private GenderType gender; > private ContactMethodType contactMethod; > public ContactMethodType getContactMethod() { > return this.contactMethod; > } > public void setContactMethod(ContactMethodType contactMethod) { > this.contactMethod = contactMethod; > } > public GenderType getGender() { > return this.gender; > } > public void setGender(GenderType gender) { > this.gender = gender; > } > > } > Superclass (Enum) > import java.io.Serializable; > import java.util.Hashtable; > import java.util.Iterator; > /** > * Base class for type-safe Enumeration to provide a consistent interface and > * common methods, and to make Castor-ation easier. > */ > public abstract class AbstractTypeSafeEnumeration implements Serializable { > private static Hashtable _types = new Hashtable(); > private String _value; > private String _displayValue; > public static final AbstractTypeSafeEnumeration getTypeByValue(String > value, Class clazz ) { > Hashtable classType = (Hashtable)_types.get(clazz.getName()); > AbstractTypeSafeEnumeration out = > (AbstractTypeSafeEnumeration)classType.get(value); > return out; > } > public static final AbstractTypeSafeEnumeration > getTypeByDisplayValue(String displayValue, Class clazz) > { > Hashtable classType = (Hashtable)_types.get(clazz.getName()); > Iterator values = classType.values().iterator(); > AbstractTypeSafeEnumeration value = null; > while (values.hasNext() && value == null) > { > AbstractTypeSafeEnumeration tempValue = > (AbstractTypeSafeEnumeration) values.next(); > if (value.getDisplayValue().equals(displayValue)) { > value = tempValue; > } > } > return value; > } > protected AbstractTypeSafeEnumeration( String value, String displayValue > ) { > this._value = value; > this._displayValue = displayValue; > synchronized( _types ) { > String className = this.getClass().getName(); > Hashtable classType = ( Hashtable )_types.get( className ); > if( classType == null ) { > classType = new Hashtable(); > _types.put( className, classType ); > } > classType.put( value, this ); > } > } > public final String getValue() { > return this._value; > } > public final String getDisplayValue() { > return this._displayValue; > } > } > Implementations of Enum (located in ContactTO) > import com.foo.to.AbstractTypeSafeEnumeration; > /** > * This class is a type-safe Enumeration of ContactMethodTypes. > * > * @author Jay Blanton > */ > public class ContactMethodType extends AbstractTypeSafeEnumeration { > public static final ContactMethodType PHONE = new ContactMethodType("P", > "Phone"); > public static final ContactMethodType MAIL = new ContactMethodType("M", > "Mail"); > public static final ContactMethodType UNKNOWN = new > ContactMethodType("U", "Unknown"); > /** > * Creates a new ContactMethodType object. > * > * @param intValue param > * @param displayString param > */ > private ContactMethodType(String value, String displayString) { > super(value, displayString); > } > } > import com.foo.to.AbstractTypeSafeEnumeration > public class GenderType extends AbstractTypeSafeEnumeration { > public static final GenderType FEMALE = new GenderType("F", "Female"); > public static final GenderType MALE = new GenderType("M", "Male"); > public static final GenderType UNKNOWN = new GenderType("U", "Unknown"); > /** > * Creates a new GenderType object. > * > * @param intValue param > * @param displayString param > */ > private GenderType(String value, String displayString) { > super(value, displayString); > } > } > This is what we would like to see: > Global Type Handler: > <typeHandler javaType="com.foo.to.AbstractTypeSafeEnumeration" > callback="com.foo.dao.datahandler.AbstractTypeSafeEnumerationTypeHandler"/> > Specific Result Map for ContactTO: > <resultMap id="loadContact" class="com.foo.to.ContactTO"> > <result property="gender" column="GENDER" jdbcType="VARCHAR" > javaType="com.foo.to.GenderType"/> > <result property="contactMethod" column="METHOD" jdbcType="VARCHAR" > javaType="com.foo.to.ContactMethodType"/> > </resultMap> > Sample of a pseudo NewTypeHandler that has access to javaType: > public class AbstractTypeSafeEnumerationTypeHandler implements NewTypeHandler > { > /** > * This method overrides the default setParameter method in TypeHandler. > * > * @param ps param > * @param i param > * @param parameter param > * @param jdbcType param > * > * @throws SQLException can be thrown > */ > public void setParameter(PreparedStatement ps, int i, Object parameter, > String jdbcType) > throws SQLException { > if(parameter == null) { > JdbcType type = > (JdbcType)JdbcType.getTypeByDisplayValue(jdbcType, JdbcType.class); > int sqlType = Integer.parseInt(type.getValue()); > ps.setNull(i, sqlType); > } > else { > AbstractTypeSafeEnumeration enum = > (AbstractTypeSafeEnumeration)parameter; > ps.setString(i, enum.getValue()); > } > } > private AbstractTypeSafeEnumeration getEnum(String value, String > javaType) { > Class clazz = null; > try { > clazz = Class.forName(javaType); > } > catch (ClassNotFoundException e) { > throw new RuntimeException("Invalid javaType - This class does > not exist: -> " + javaType, e); > } > return AbstractTypeSafeEnumeration.getTypeByValue(value, clazz); > } > > /** > * This method overrides the default getResult method in TypeHandler. > * > * @param rs param > * @param columnName param > * > * @return returned > * > * @throws SQLException can be thrown > */ > public Object getResult(ResultSet rs, String columnName, String javaType) > throws SQLException { > String result = rs.getString(columnName); > return this.getEnum(result, javaType); > } > /** > * This method overrides the default getResult method in TypeHandler. > * > * @param rs param > * @param columnIndex param > * > * @return returned > * > * @throws SQLException can be thrown > */ > public Object getResult(ResultSet rs, int columnIndex, String javaType) > throws SQLException { > String result = rs.getString(columnIndex); > return this.getEnum(result, javaType); > } > /** > * This method overrides the default getResult method in TypeHandler. > * > * @param cs param > * @param columnIndex param > * > * @return returned > * > * @throws SQLException can be thrown > */ > public Object getResult(CallableStatement cs, int columnIndex, String > javaType) > throws SQLException { > String result = cs.getString(columnIndex); > return this.getEnum(result, javaType); > } > /** > * This method overrides the default equals method in TypeHandler. > * > * @param object param > * @param dbVal param > * > * @return returned > */ > public boolean equals(Object object, String dbVal) { > return > StringHelper.equals(((AbstractTypeSafeEnumeration)object).getValue(), dbVal); > } > /** > * This method overrides the default valueOf method in TypeHandler. > * > * @param dbVal param > * > * @return returned > */ > public Object valueOf(String dbVal) { > return dbVal; > } > } > -- This message is automatically generated by JIRA. - If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa - For more information on JIRA, see: http://www.atlassian.com/software/jira