1.概述
Castor的自定义映射关系通过XML设置。
主要作用有
1)改变映射位置(node): attribute, element, text
2)改变映射名字(name...): attributeName, elementTagName
3)改变层级关系(location)
4)改变输出格式(handler): dateFormat...
5)改变属性获取和设置方式(get/setMethod, direct="true")
6)隐藏属性(auto-complete="true", transient="true")
2.源码
Address.java Student.java 详见 Castor (一) -- 默认绑定
LocalDateHandler.java
package com.siyuan.castor.handler;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.exolab.castor.mapping.FieldHandler;
import org.exolab.castor.mapping.ValidityException;
import com.siyuan.castor.Student;
public class LocalDateHandler implements FieldHandler {
private static final String LOCAL_DATE_FORMAT = "yyyy-MM-dd";
public void checkValidity(Object object) throws ValidityException,
IllegalStateException {
}
/**
* @param object the owner of the field
*/
public Object getValue(Object object) throws IllegalStateException {
if (object instanceof Student) {
Date date = ((Student) object).getBirthday();
if (date != null) {
DateFormat dateFmt = new SimpleDateFormat(LOCAL_DATE_FORMAT);
return dateFmt.format(date);
} else {
return null;
}
}
return null;
}
public Object newInstance(Object arg0) throws IllegalStateException {
return null;
}
public void resetValue(Object arg0) throws IllegalStateException,
IllegalArgumentException {
}
/**
* @param object the owner of the field
* @param dateString the field value in the xml source file
*/
public void setValue(Object object, Object dateString)
throws IllegalStateException, IllegalArgumentException {
if (object instanceof Student) {
DateFormat dateFmt = new SimpleDateFormat(LOCAL_DATE_FORMAT);
try {
Date date = dateFmt.parse((String) dateString);
((Student) object).setBirthday(date);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
}
}
DivDateHandler.java
package com.siyuan.castor.handler;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.exolab.castor.mapping.GeneralizedFieldHandler;
public class DivDateHandler extends GeneralizedFieldHandler {
private static final String LOCAL_DATE_FORMAT = "yyyy-MM-dd";
/**
* automatically supports iterating over the items of a collection
* and passing them one-by-one to the convertUponGet
*
* setCollectionIteration : could modify it
*/
public DivDateHandler() {
setCollectionIteration(false);
}
/**
* @Override
* @param value the object value to convert after
* performing a get operation
* @return the converted value.
*/
public Object convertUponGet(Object value) {
if (value == null)
return null;
DateFormat dateFmt = new SimpleDateFormat(LOCAL_DATE_FORMAT);
return dateFmt.format((Date) value);
}
/**
* @Override
* @param value the object value to convert before
* performing a set operation
* @return the converted value.
*/
public Object convertUponSet(Object value) {
if (value == null)
return null;
DateFormat dateFmt = new SimpleDateFormat(LOCAL_DATE_FORMAT);
Date date = null;
try {
date = dateFmt.parse((String) value);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
return date;
}
/**
* @Override
* Returns the class type for the field that this
* GeneralizedFieldHandler converts to and from. This
* should be the type that is used in the
* object model.
*
* @return the class type of of the field
*/
public Class getFieldType() {
return Date.class;
}
}
ConfigureDateHandler.java
package com.siyuan.castor.handler;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import org.exolab.castor.mapping.ConfigurableFieldHandler;
import org.exolab.castor.mapping.FieldHandler;
import org.exolab.castor.mapping.ValidityException;
import com.siyuan.castor.Student;
public class ConfigureDateHandler implements FieldHandler,
ConfigurableFieldHandler {
private static final String DATE_FORMAT_PARAM_NAME = "date-format";
private DateFormat dateFormat;
public void checkValidity(Object arg0) throws ValidityException,
IllegalStateException {
}
public Object getValue(Object object) throws IllegalStateException {
if (object instanceof Student) {
Date date = ((Student) object).getBirthday();
if (date != null) {
return dateFormat.format(date);
} else {
return null;
}
}
return null;
}
public Object newInstance(Object arg0) throws IllegalStateException {
return null;
}
public void resetValue(Object arg0) throws IllegalStateException,
IllegalArgumentException {
}
public void setValue(Object object, Object dateString)
throws IllegalStateException, IllegalArgumentException {
if (object instanceof Student) {
try {
Date date = dateFormat.parse((String) dateString);
((Student) object).setBirthday(date);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
}
/**
* @param params configure information in the xml
*/
public void setConfiguration(Properties params) throws ValidityException {
String pattern = params.getProperty(DATE_FORMAT_PARAM_NAME);
if (pattern == null)
throw new ValidityException("Required parameter \"" + DATE_FORMAT_PARAM_NAME + "\" is missing");
try {
dateFormat = new SimpleDateFormat(pattern);
} catch (IllegalArgumentException e) {
throw new ValidityException("Pattern \"" + pattern + "\" is not a valid date format.");
}
}
}
Student.cst.xml
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Object Mapping DTD Version 1.0//EN" "http://castor.exolab.org/mapping.dtd"> <mapping> <description>Used for com.siyuan.castor.Student</description> <!-- <include href=""></include> --> <!-- <field-handler /> --> <field-handler name="localDateHandler" class="com.siyuan.castor.handler.ConfigureDateHandler"> <param name="date-format" value="yyyy-MM-dd"/> </field-handler> <!-- verify-constructable="false" used with the set-method="%1-9%" make it able to omit the no-parameter constructor --> <class name="com.siyuan.castor.Student" auto-complete="true"> <description>com.siyuan.castor.Student</description> <map-to xml="Person"/> <!-- type="java.lang.String" handler="" required="true" direct="true" transient="true" set-method="%1-9%" get-method="getName" type="string" //can not omit the no-parameter constructor --> <field name="name"> <description>property name</description> <bind-xml name="stuName" node="attribute"/> </field> <!-- type="string" handler="com.siyuan.castor.handler.DivDateHandler" type="string" handler="com.siyuan.castor.handler.LocalDateHandler" //type could not be omitted and must be string location="birthday/birthday1" --> <field name="birthday" type="string" handler="localDateHandler"> <bind-xml name="birth" node="attribute"/> </field> <field name="friends" collection="set" type="com.siyuan.castor.Student" get-method="getFriends" set-method="addFriend"> <bind-xml name="friend" node="element"/> </field> <field name="subjects" collection="arraylist" type="string" get-method="getSubjects" set-method="addSubject"> <bind-xml name="subjects" node="element"/> </field> <field name="teachers" collection="map"> <bind-xml name="teachers" node="element"> <class name="org.exolab.castor.mapping.MapItem"> <field name="key" type="java.lang.String"> <bind-xml name="name" node="attribute"/> </field> <field name="value" type="java.lang.String"> <bind-xml name="subject" node="attribute"/> </field> </class> </bind-xml> </field> </class> <!-- not used for XML mapping <key-generator /> --> </mapping>
CastorDIYTest.java
package com.siyuan.castor.test;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
import org.xml.sax.InputSource;
import com.siyuan.castor.Address;
import com.siyuan.castor.Student;
public class CastorDIYTest {
/**
* @param args
* @throws ValidationException
* @throws MarshalException
* @throws ValidationException
* @throws MarshalException
*/
public static void main(String[] args) throws MarshalException, ValidationException{
Student stuSrc = new Student();
stuSrc.setAge(22);
stuSrc.setName("SingleMan");
stuSrc.setMale(true);
Address address = new Address();
address.setStreet("Renmin Road");
stuSrc.setAddress(address);
DateFormat dateFmt = new SimpleDateFormat("yyyy-MM-dd");
try {
Date birthday = dateFmt.parse("1988-11-21");
stuSrc.setBirthday(birthday);
} catch (ParseException e) {
e.printStackTrace();
}
Student girl = new Student();
girl.setAge(20);
stuSrc.setGirlFriend(girl);
Set<Student> students = new HashSet<Student>();
Student stu1 = new Student();
stu1.setAge(21);
students.add(stu1);
Student stu2 = new Student();
stu2.setAge(23);
students.add(stu2);
stuSrc.addFriend(stu1);
stuSrc.addFriend(stu2);
stuSrc.addSubject("English");
stuSrc.addSubject("Math");
stuSrc.addSubject("Chinese");
Map<String, String> teachers = new HashMap<String, String>();
teachers.put("English", "teacher a");
teachers.put("Math", "teacher b");
teachers.put("Chinese", "teacher c");
stuSrc.setTeachers(teachers);
Mapping mapping = new Mapping();
try {
InputStream mappingFileIn = Student.class
.getResourceAsStream("/com/siyuan/castor/Student.cst.xml");
mapping.loadMapping(new InputSource(mappingFileIn));
StringWriter result = new StringWriter();
Marshaller marshaller = new Marshaller();
marshaller.setMapping(mapping);
marshaller.setWriter(result);
marshaller.marshal(stuSrc);
System.out.println(result);
System.out.println("=================================================================");
Unmarshaller unmarshaller = new Unmarshaller(mapping);
Student stuDist = (Student) unmarshaller.unmarshal(new StringReader(result.toString()));
System.out.println(stuDist);
} catch (MappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 输出结果
<?xml version="1.0" encoding="UTF-8"?>
<Person stuName="SingleMan" birth="1988-11-21" male="true" age="22"><friend male="false" age="23"/><friend male="false" age="21"/><subjects>English</subjects><subjects>Math</subjects><subjects>Chinese</subjects><teachers name="English" subject="teacher a"/><teachers name="Math" subject="teacher b"/><teachers name="Chinese" subject="teacher c"/><girl-friend male="false" age="20"/><address><street>Renmin Road</street></address></Person>
=================================================================
Student[name=SingleMan,age=22,male=true,birthday=Mon Nov 21 00:00:00 CST 1988,
address=Address[street=Renmin Road],
girlFriend=Student[name=null,age=20,male=false,birthday=null,
address=null,
girlFriend=null,
friends=[],
subjects=[],
teachers={}
],
friends=[Student[name=null,age=23,male=false,birthday=null,
address=null,
girlFriend=null,
friends=[],
subjects=[],
teachers={}
], Student[name=null,age=21,male=false,birthday=null,
address=null,
girlFriend=null,
friends=[],
subjects=[],
teachers={}
]],
subjects=[English, Math, Chinese],
teachers={English=teacher a, Math=teacher b, Chinese=teacher c}
]
4.参考资料
http://www.castor.org/xml-mapping.html
http://www.castor.org/xml-fieldhandlers.html#Use-ConfigurableFieldHandler-for-more-flexibility
附件为mapping文件对应的DTD和XSD文件