简要分析Java的Hibernate框架中的自定义类型

最近看到hibernate的自定义类型,这个以前没接触过,在这里记录一下,当是对自己知识的巩固,也让没有接触过的朋友一起学习研究一番。

 1)自定义类型,顾名思义,当然就是由于内部的类型不满足需求,而自己来进行实现的类型。这种情况不多,但我们还是有必要学习一下,技多不压身嘛。也学习一下,别人在做框架的时候是怎么去考虑的,怎么去思考扩展性的。

 自定义类型有两个方法来实现,一种是实现UserType,另外一种实现CompositeUserType,另外可能还有一些方法,但我暂时没用到,先不讲了。

 我暂时只用到UserType,我们就先看一下UserType接口的定义:

public interface UserType {

/**

* Return the SQL type codes for the columns mapped by this type. The

* codes are defined on <tt>java.sql.Types</tt>.

*/

public int[] sqlTypes();

/**

* The class returned by <tt>nullSafeGet()</tt>.

*/

public Class returnedClass();

/**

* Compare two instances of the class mapped by this type for persistence "equality".

* Equality of the persistent state.

*/

public boolean equals(Object x, Object y) throws HibernateException;

/**

* Get a hashcode for the instance, consistent with persistence "equality"

*/

public int hashCode(Object x) throws HibernateException;

/**

* Retrieve an instance of the mapped class from a JDBC resultset. Implementors

* should handle possibility of null values.

*/

public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException;

/**

* Write an instance of the mapped class to a prepared statement. Implementors

* should handle possibility of null values. A multi-column type should be written

* to parameters starting from <tt>index</tt>.

*/

public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException;

/**

* Return a deep copy of the persistent state, stopping at entities and at

* collections. It is not necessary to copy immutable objects, or null

* values, in which case it is safe to simply return the argument.

*/

public Object deepCopy(Object value) throws HibernateException;

/**

* Are objects of this type mutable?

*

* @return boolean

*/

public boolean isMutable();

/**

* Transform the object into its cacheable representation. At the very least this

* method should perform a deep copy if the type is mutable. That may not be enough

* for some implementations, however; for example, associations must be cached as

* identifier values. (optional operation)

*

* @param value the object to be cached

* @return a cachable representation of the object

* @throws HibernateException

*/

public Serializable disassemble(Object value) throws HibernateException;

/**

* Reconstruct an object from the cacheable representation. At the very least this

* method should perform a deep copy if the type is mutable. (optional operation)

*/

public Object assemble(Serializable cached, Object owner) throws HibernateException;

/**

* During merge, replace the existing (target) value in the entity we are merging to

* with a new (original) value from the detached entity we are merging. For immutable

* objects, or null values, it is safe to simply return the first parameter. For

* mutable objects, it is safe to return a copy of the first parameter. For objects

* with component values, it might make sense to recursively replace component values.

*/

public Object replace(Object original, Object target, Object owner) throws HibernateException;

}

  其实大家看英文一般情况下都能理解,不再多做解释了,这里我们最主要的就是实现nullSafeSet() 方法,这个方法主要用到把此类型的值保存到数据库,这一次我们先学怎么用,以后我们再慢慢研究内部是怎么来实现的。

 2)我学习时写的例子是参照夏昕的例子,所以肯定和网上的大部分都一样,我们只是大概分析一下:

 下面是User类

package org.hibernate.tutorial.domain;

import java.io.Serializable;

import java.util.List;

public class User implements Serializable{

public Long id;

private String name;

private List emails;

省略Get/Set方法

}

  下来是自定义的EmailList类:

package org.hibernate.tutorial.domain;

import java.io.Serializable;

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.hibernate.Hibernate;

import org.hibernate.HibernateException;

import org.hibernate.usertype.UserType;

public class EmailList implements UserType {

private static final char SPLITTER = ';';

private static final int[] TYPES = new int[] {Types.VARCHAR};

private String assemble(List emailList) {

StringBuilder strBuf = new StringBuilder();

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 = org.hibernate.util.StringHelper.split(value,String.valueOf(SPLITTER));

List emailList = new ArrayList();

for (int i = 0;i < strs.length; i++) {

emailList.add(strs[i]);

}

return emailList;

}

public Object deepCopy(Object value) throws HibernateException {

List sourceList = (List)value;

List targetList = new ArrayList();

targetList.add(sourceList);

return targetList;

}

public Serializable disassemble(Object value) throws HibernateException {

return null;

}

public boolean equals(Object x, Object y) throws HibernateException {

if (x == y) return true;

System.out.println("X:"+x+"Y:"+y);

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;

}

public boolean isMutable() {

return false;

}

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);//把List通过;分割

} else{

return null;

}

}

public void nullSafeSet(PreparedStatement st, Object value, int index)

throws HibernateException, SQLException {

System.out.println("Set Method Executed!");

System.out.println("value:" + value);

if (value != null){

String str = assemble((List)value);//把字符串用;拼接

Hibernate.STRING.nullSafeSet(st, str, index);

} else {

Hibernate.STRING.nullSafeSet(st, value, index);

}

}

public Class returnedClass() {

return List.class;

}

public int[] sqlTypes() {

return TYPES;

}

//省略其他不需要修改的方法

}

  类中实现的方法是需要修改的方法,其他不需要修改暂时不用的方法则没有写出来,但还是需要实现的。

 3)接下来就是User类的映射文件:

<class name="User" table="USER">

<id name="id" column="USER_ID" type="java.lang.Long">

<generator class="native" />

</id>

<property name="name" type="string" column="USER_NAME"/>

<property name="emails" type="org.hibernate.tutorial.domain.EmailList" column="emails"/>

</class>

  相信大家都知道怎么进行修改,这里也不进行讲解了,主要是修改emails的type,修改为我们刚才定义的EmailList类。

 4)最后我们来写一个测试类:

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.ArrayList;

import junit.framework.TestCase;

import org.hibernate.EntityMode;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.hibernate.Transaction;

import org.hibernate.cfg.Configuration;

import org.hibernate.tutorial.domain.User;

public class HibernateTest extends TestCase{

private Session session = null;

protected void setUp() throws Exception {

Configuration cfg = new Configuration().configure();

SessionFactory sessionFactory = cfg.buildSessionFactory();

session = sessionFactory.openSession();

}

public void testInsert(){

Transaction tran = null;

try{

tran = session.beginTransaction();

User user = new User();

user.setName("shun");

List list = new ArrayList();

list.add("12312@sfsdf.com");

list.add("123@123.com");

user.setEmails(list);

session.save(user);

tran.commit();

} catch (Exception ex) {

ex.printStackTrace();

if (tran != null){

tran.rollback();

}

}

}

protected void tearDown() throws Exception {

session.close();

}

}

  这里可能会出现问题,当我们只保存一个email时,它会出现异常,在数据库里面是email字段是空的,而当我们如上面代码一样,有两个时,并不会出现问题,数据库中结果如图:

而当我们只保存一个时,异常如下:

java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String

 它发生在EmailList的equals方法中的String str1 = (String)xList.get(i);这句代码中,经检查是在插入数据传到EmailList的nullSafeSet方法时变成了List的List,即

value:[[12312@sfsdf.com, 123@123.com]]这样的形式,这样在比较的时候就会出问题,它永远都只有一个值,而在比较的时候却是不同的,

if(xList.size() != yList.size()) return false;

 所以在强制转换时会出问题。

 而经过检查,equals方法里:

 

X:[[12312@sfsdf.com, 123@123.com]]Y:[12312@sfsdf.com, 123@123.com]

 这样的结果却是很奇怪的。网上并没有讲到为什么会出现这种情况。这里提出一下:我用的hibernate版本是Hibernate 3.3.2.GA。不知道是版本问题还是其他问题,我们明天再研究一下。如果有哪位兄弟知道为什么的,希望也不吝告诉我一下。

以上是 简要分析Java的Hibernate框架中的自定义类型 的全部内容, 来源链接: utcz.com/p/208297.html

回到顶部