How to use a parameterized class as resultClass in iBATIS
We have the following class
public class TemporalData<T> {
private T data;
private String opCode;
private Date updateTime;
// getters, setters
}
public class Employee {
private String name;
private int age;
private Date dob;
// getters, setters
}
And say, we've an employee_log table with all fields of employee and couple of additional columns (opCode, updateTime)
Assume this is a pattern for all log tables where we have few additional columns (in this case opCode, updateTime), we would like to ha开发者_运维技巧ve one single class that can cater to all Temporal data and hence the parameterized class.
Now, if we have to fetch employees whose attributes changed in a given duration and would like to have objects of type TemporalData returned by the DAO layer, can anyone explain how to implement an ibatis TypeHandler to handle this case? How should the type handler be configured in sqlmap xml files?
Got to know a much better and simpler solution from one of my colleagues.
<resultMap class="Employee" id="employee">
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="bidPrice" column="bid_price"/>
<result property="dob" column="dob"/>
</resultMap>
<resultMap class="Temporal" id="temporalEmployee">
<result property="data" resultMap="employee"/>
<result property="opCode" column="opCode" javaType="String"/>
<result property="updateTime" column="updateTime" javaType="java.util.Date"/>
</resultMap>
The above approach would work well without any additional components.
After a lot of digging through ibatis classes in multiple packages , the following approach worked for me. (couldn't find any documentation regarding this approach nor any content in the only book available for ibatis - ibatis in action)
Step 1: Add a custom ResultObjectFactory. Classdoc of ResultObjectFactory interface explains what it is and how it behaves.
public class TemporalDataResultObjectFactory implements ResultObjectFactory {
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactory#createInstance
* (java.lang.String, java.lang.Class)
*/
@Override
public Object createInstance(String statementId,
@SuppressWarnings("rawtypes") Class clazz)
throws InstantiationException, IllegalAccessException {
if (!statementId.startsWith("_td_")) {
return null;
}
TemporalData<Object> temporalResult = new TemporalData<Object>();
Object dataObject = clazz.newInstance();
temporalResult.setData(dataObject);
return temporalResult;
}
/*
* (non-Javadoc)
*
* @see
* com.ibatis.sqlmap.engine.mapping.result.ResultObjectFactory#setProperty
* (java.lang.String, java.lang.String)
*/
@Override
public void setProperty(String arg0, String arg1) {
// TODO Auto-generated method stub
}
}
Step 2: Add the above ResultObjectFactory to sql-map-config
<resultObjectFactory type="TemporalDataResultObjectFactory" />
Step 3: Prefix all your ibatis statement Ids whose result is temporal data with 'td'.
example:
<select id="_td_getTemporalEmployees" resultMap="temporalEmployee">
SELECT name, age, opCode, updateTime
FROM employee
WHERE updateTime BETWEEN #startTime# AND #endTime#
</select>
Step 4: Define the result map with the actual class (eg: if you want the result to be TemporalData, then set the class to 'Employee'), but with properties as per the temporalData class.
example:
<resultMap class="Employee" id="temporalEmployee">
<result property="data.name" column="name" javaType="String"/>
<result property="data.age" column="age" javaType="long"/>
<result property="data.bidPrice" column="bid_price" javaType="int"/>
<result property="data.dob" column="dob" javaType="java.util.Date"/>
<result property="opCode" column="opCode" javaType="String"/>
<result property="updateTime" column="updateTime" javaType="java.util.Date"/>
</resultMap>
Step 5: Make sure that all properties in resultMap defined above has javaType appropriately set (Otherwise, ibatis throws exceptions during validations complaining about unavailable setters)
精彩评论