import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import net.sf.hibernate.HibernateException;

/**
* @author hy-he
*
*/
public interface UserType {
/**
* 返回UserType所映射字段的SQL类型(java.sql.Types)
* 返回类型为int[],其中包含了映射个字段的SQL类型代码
* (UserType可以映射到一个或者多个字段)
* @return
*/
public int[]sqlTypes();
/**
* UserType.nullSafeGet()所返回的自定义数据类型
* @return
*/
public Class returnedClass();
/**
* 自定义数据类型的比对方法
* 此方法将用作脏数据检查,参数x、y分别为数据的两个副本
* 如果equals方法返回false,则Hibernate将认为数据发生变化,并将变化更新到数据库表中
* @param x
* @param y
* @return
* @throws HibernateException
*/
public boolean equals(Object x,Object y)throws HibernateException;
/**
* 从JDBC ResultSet读取数据,将其转换为自定义类型后返回
* (此方法要求对克能出现null值进行处理)
* names中包含了当前自定义类型的映射字段名称
* @param rs
* @param names
* @param owner
* @return
* @throws HibernateException
* @throws SQLException
*/
public Object nullSafeGet(ResultSet rs,String[] names,Object owner)throws HibernateException,SQLException;
/**
* 本方法将在Hibernate进行数据保存时被调用
* 我们可以通过PreparedStateme将自定义数据写入到对应的数据库表字段
* @param st
* @param value
* @param index
* @throws HibernateException
* @throws SQLException
*/
public void nullSafeSet(PreparedStatement st,Object value,int index)throws HibernateException,SQLException;
/**
* 提供自定义类型的完全复制方法
* 本方法将用构造返回对象
* 当nullSafeGet方法调用之后,我们获得了自定义数据对象,在向用户返回自定义数据之前,
* deepCopy方法将被调用,它将根据自定义数据对象构造一个完全拷贝,并将此拷贝返回给用户
* 此时我们就得到了自定义数据对象的两个版本,第一个是从数据库读出的原始版本,其二是我们通过
* deepCopy方法构造的复制版本,原始的版本将有Hibernate维护,复制版由用户使用。原始版本用作
* 稍后的脏数据检查依据;Hibernate将在脏数据检查过程中将两个版本的数据进行对比(通过调用
* equals方法),如果数据发生了变化(equals方法返回false),则执行对应的持久化操作
*
* @param value
* @return
* @throws HibernateException
*/
public Object deppCopy(Object value)throws HibernateException;
/**
* 本类型实例是否可变
* @return
*/
public boolean isMutable();
}



1.实现UserType接口的EMailList自定义类型

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import net.sf.hibernate.Hibernate;
import net.sf.hibernate.HibernateException;
import net.sf.hibernate.UserType;
import net.sf.hibernate.hql.Parser;

/**
* @author hy-he
*
*/
public class EMailList implements UserType {
private List emails;
private static final String SPLITTER = ";";
private static final int[] TYPES = new int[]{
Types.VARCHAR
};
/* (non-Javadoc)
* @see net.sf.hibernate.UserType#sqlTypes()
*/
public int[] sqlTypes() {
// TODO Auto-generated method stub
return TYPES;
}

/* (non-Javadoc)
* @see net.sf.hibernate.UserType#returnedClass()
*/
public Class returnedClass() {
// TODO Auto-generated method stub
return List.class;
}

/* (non-Javadoc)
* @see net.sf.hibernate.UserType#equals(java.lang.Object, java.lang.Object)
*/
public boolean equals(Object x, Object y) throws HibernateException {
if(x == y) return true;
if(x != null && y != null){
List xList = (List)x;
List yList = (List)y;
if(xList.size() != yList.size()) return false;
for(int i = 0;i<xList.size();i++){
String str1 = (String)xList.get(i);
String str2 = (String)yList.get(i);
if(!str1.equals(str2)) return false;
}
return true;
}
return false;
}

/* (non-Javadoc)
* @see net.sf.hibernate.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
*/
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
String value = (String)Hibernate.STRING.nullSafeGet(rs,names[0]);
if( value != null){
return parse(value);
}else{
return null;
}
}

/* (non-Javadoc)
* @see net.sf.hibernate.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
*/
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException {
System.out.println("Set method excecuted");
if(value != null){
String str = assemble((List)value);
Hibernate.STRING.nullSafeSet(st,str,index);
}else{
Hibernate.STRING.nullSafeSet(st,value,index);
}

}

/* (non-Javadoc)
* @see net.sf.hibernate.UserType#deepCopy(java.lang.Object)
*/
public Object deepCopy(Object value) throws HibernateException {
List sourcelist = (List)value;
List targetlist = new ArrayList();
targetlist.addAll(sourcelist);
return targetlist;
}

/* (non-Javadoc)
* @see net.sf.hibernate.UserType#isMutable()
*/
public boolean isMutable() {
// TODO Auto-generated method stub
return false;
}
private String assemble(List emailList){
StringBuffer strBuf = new StringBuffer();
for(int i = 0;i<emailList.size()-1;i++){
strBuf.append(emailList.get(i)).append(SPLITTER);
}
strBuf.append(emailList.get(emailList.size()-1));
return strBuf.toString();
}
private List parse(String value){
String[] strs = StringUtils.split(value,SPLITTER);
List emailList = new ArrayList();
for(int i = 0;i<strs.length;i++){
emailList.add(strs[i]);
}
return emailList;
}
}

2.POJO:


import java.io.Serializable;
import java.util.List;

/**
* @author hy-he
* @hibernate.class
* table = "USER_TYPE_USER"
*/
public class UserTypeUser implements Serializable {
private Long id;
private String name;
private Integer age;
private List email = new ArrayList();
/**
* @hibernate.id
* column = "USER_ID"
* generator-class = "increment"
* @return
*/
public Long getId() {
return id;
}
/**
* @hibernate.property
* column = "AGE"
* @return
*/
public Integer getAge() {
return age;
}
/**
* @hibernate.property
* column = "EMAIL"
* type = "hibernate.usertype.EMailList"
* @return
*/
public List getEmail() {
return email;
}
/**
* @hibernate.property
* column = "NAME"
* @return
*/
public String getName() {
return name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setEmail(List email) {
this.email = email;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}

}
3.xml:

<?xml version="1.0"?>

<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">

<hibernate-mapping>
<class
name="hibernate.usertype.UserTypeUser"
table="USER_TYPE_USER"
dynamic-update="false"
dynamic-insert="false"
>

<id
name="id"
column="USER_ID"
type="java.lang.Long"
>
<generator class="increment">
</generator>
</id>

<property
name="age"
type="java.lang.Integer"
update="true"
insert="true"
access="property"
column="AGE"
/>

<property
name="email"
type="hibernate.usertype.EMailList"
update="true"
insert="true"
access="property"
column="EMAIL"
/>

<property
name="name"
type="java.lang.String"
update="true"
insert="true"
access="property"
column="NAME"
/>

<!--
To add non XDoclet property mappings, create a file named
hibernate-properties-UserTypeUser.xml
containing the additional properties and place it in your merge dir.
-->

</class>

</hibernate-mapping>
4.运用:

insert方法:

public static void insertUser() throws HibernateException {
UserTypeUser user = new UserTypeUser();
user.setAge(new Integer(23));
user.setName("Test UserType");
user.getEmail().add("rever@hotmail.com");
user.getEmail().add("rever1@hotmail.com");
user.getEmail().add("rever2@hotmail.com");
user.getEmail().add("rever3@hotmail.com");
Session session = HibernateUtil.currentSession();
Transaction tx = session.beginTransaction();
session.save(user);

tx.commit();
HibernateUtil.closeSession();
}

display方法:

public static void display() throws HibernateException {
Session session = HibernateUtil.currentSession();
List users = session.find("from UserTypeUser");
HibernateUtil.closeSession();

for (ListIterator iterator = users.listIterator(); iterator.hasNext();) {
UserTypeUser pu = (UserTypeUser) iterator.next();
System.out.println(pu.getName());
List emails = pu.getEmail();
for(int i = 0;i<emails.size();i++){
System.out.println(emails.get(i));
}
}
}