In a previous post, I provided iBatis configuration and mapping that supported populating Java objects on a per-property basis, i.e. the classes in use had to provide setters for this approach. Here I describe another iBatis pattern that populates immutable objects with more than a few properties.
First, I assume the target object uses the Builder Pattern to support construction, since this is a useful approach for immutable classes exposing, as mentioned, "more than a few properties".
Continuing from my original example, the iBatis mapping might look something like this (I omit the one-to-many issue from my original post since that's not crucial to this discussion):
<mapper namespace="com.mybiz.Student">
<resultMap id="student-info" type="map">
<result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
<result property="email" column="email" javaType="String" jdbcType="VARCHAR"/>
<result property="gmail" column="email" javaType="String" jdbcType="VARCHAR"/>
<result property="cellPhone" column="completed" javaType="String" jdbcType="VARCHAR"/>
<result property="landlinePhone" column="completed" javaType="String" jdbcType="VARCHAR"/>
<result property="googleVoicePhone" column="completed" javaType="String" jdbcType="VARCHAR"/>
<result property="gender" column="email" javaType="String" jdbcType="VARCHAR"/>
<result property="ssn" column="completed" javaType="String" jdbcType="VARCHAR"/>
<result property="ethnicity" column="completed" javaType="String" jdbcType="VARCHAR"/>
</resultMap>
<sql id="fields">
name, email, gmail, cellPhone, landlinePhone, googleVoicePhone, gender, ssn, ethnicity
</sql>
<select id="getStudentInfo" parameterClass="string" resultMap="student-info">
select
<include refid="fields"/>
from STUDENT where email = #value#
</select>
</mapper>
This mapping, in a file named e.g. student.xml, is referenced as usual in the top-level iBatis config file:
<configuration>
<mappers>
<mapper resource="com/mybiz/student.xml"/>
</mappers>
</configuration>
I'll omit the boilerplate around consuming the iBatis configuration and obtaining an iBatis session factory. Let's just go with the "miracle occurs here" approach, and cut to the Java-side chase - this first provides an interface with full classname matching the iBatis mapper namespace and a method with name matching the iBatis select statement id:
package com.mybiz;
public interface Student
{
String getStudentInfo(String email);
}
The iBatis session factory is used to open the session and obtain a concrete instance of the mapper:
SqlSession session = sessionFactory.openSession();
Student mapper = session.getMapper(Student.class);
The mapper returns a map that can be used to populate the target (immutable, remember?) object:
List<Map<String, ?>> resultMap = mapper.getStudentInfo("joe@joe.com");
Finally, we extract values from the map and use these in an invocation of the builder for the Student object, addressing only those properties we care about:
for (Map<String, ?> result : resultMap) {
String name = (String) result.get("name");
String email = (String) result.get("email");
String gmail = (String) result.get("gmail");
String ethnicity = (String) result.get("ethnicity");
String cellPhone = (String) result.get("cellPhone");
String gender = (String) result.get("gender");
Student student = new Student.Builder(new Email(email)) // email is the only required value
.name(name)
.gmail(gmail)
.ethnicity(ethnicity)
.cellPhone(cellPhone)
.gender(gender)
.build();
}
Again, please refer to my post around the builder pattern to get details on how I designed the Student class to work in the above example.
No comments:
Post a Comment