Here is an example of how to set up a custom type handler with a complex property. This example uses the enum features of Java 1.5 but could be used with a Type Safe Enumeration in anything below 1.5.
Lets start by defining the database table
SHAPE {
name varchar2(25),
color number(100)
}
As you see the color is stored as a number, but in the class Shape is is a Color object. There are two question that I ran into. First, how do you cleanly map the number stored in the database with the instance of a Color? Second, how can iBatis and custom type handlers help?
To answer the first let me show you the code for the Shape class.
/*
* Shape.java
*
* Created on September 23, 2005
*/
package domain;
/**
*
* @author nmaves
*/
public class Shape {
public enum Color {
BLUE(1, "0000FF"), RED(2, "FF0000"), GREEN(3, "00FF00");
private int id;
private String rgb;
private Type(int id, String name) {
this(id, name, "no mime type");
}
private Type(int id, String rgb) {
this.id = id;
this. rgb = rgb;
}
public int getId() {
return this.id;
}
public String getRGB() {
return this.name;
}
public static Type getInstance(int i) {
for(Color color : Color.values()) {
if(color.id == i) {
return type;
}
}
throw new IllegalArgumentException("No such Color");
}
}
private String name;
private Color color;
/** Creates a new instance of Frequency */
private Shape(String name, Color color) {
this.color = color;
this.name = name;
}
public String toString() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public void setColor(Color color) {
this.color = color;
}
public String getName() {
return this.name;
}
public Color getColor() {
return this.color;
}
}
As you see the getInstance(int i) method allows for the mapping of the number stored in the database to an instance of this class. I am sure there is a better way of pulling these initial value from a properties file but this is only an example.
For the second part you will need a way to allow iBatis to make the conversion. This is where the custom type handler comes into play.
Below is my ColorTypeHandler.java
package dao.ibatis; import com.ibatis.sqlmap.client.extensions.ParameterSetter; import com.ibatis.sqlmap.client.extensions.ResultGetter; import com.ibatis.sqlmap.client.extensions.TypeHandlerCallback; import java.sql.SQLException; import java.sql.Types; import Shape.Color; public class ColorTypeHandler implements TypeHandlerCallback { public Object getResult(ResultGetter getter) throws SQLException { int value = getter.getInt(); if (getter.wasNull()) { return null; } Color color = Color.getInstance(value); return color; } public void setParameter(ParameterSetter setter, Object parameter) throws SQLException { if (parameter == null) { setter.setNull(Types.INTEGER); } else { Color color = (Color) parameter; setter.setInt(color.getId()); } } public Object valueOf(String s) { return s; } }
You are almost there! All you need left to do is tell iBatis to map instances of Frequency object to this handler.
I added the following line into my SqlMapConfig file.
<typeHandler javaType="domain.Shape$Color" callback="dao.ibatis.ColorTypeHandler"/>
| Useful Information Notice the $ in the class name. This is how Java 1.5 denotes enums. If this were a type safe enum you would just use standard notation. |
That is it. No need to change any of your other sqlmap entries. Here is an example of a select and insert that use this handler.
<resultMap class="Shape" id="ShapeResult"> <result column="name" property="name" /> <result column="color" property="color" /> </resultMap> <select id="getShapeByName" parameterClass="string" resultMap="ShapeResult"> SELECT * FROM SHAPE WHERE name = #value# </select> <insert id="insertReport" parameterClass="Report"> INSERT INTO SHAPE ( name, color ) values ( #name#, #color#, ) </insert>
Notice that there is nothing special that need to be done for the color columns.
