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.