浏览 2871 次
|
锁定老贴子 主题:扩展hibernate,使用自己的集合类
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
最后更新时间:2008-07-21 关键字: 扩展
/**
*作者:张荣华(ahuaxuan) *2007-04-24 *转载请注明出处及作者 */ Hibernate在使用关联集合的时候有自己的几种类型,分别是set,list,map,bag等,而对应的hibernate实现是PersistentSet, PersistentList, PersistentBag等,几种集合类型的使用场合问题并不是今天要讨论的话题,今天要讨论的是如何在程序中使用我们自己写的集合类型,这一点 当然很多人人会质疑这样做的必要性,他们会问hibernate提供的集合类型已经够用了,为什么还要自己扩展呢? 事实上在有些情况下使用自己的集合类型是非常重要的,比如说(下面我们就以PersistentSet类举例,其他集合类情况类似) PersistentSet类并没有序列化id,也就是说在分布式环境中如果两边的jvm版本不一样,那么没有序列化id的话,序列化一方会采用自己默认的序列化id,而反序列化一方的也会采用自己的默认的序列化id,而这两个id一般是不一样的,导致一方序列化之后另一方就无法进行正常的反序列化。当然我想应该还有其他情况需要这种扩展的,所以把它共享出来。 考虑到直接修改源代码可能和开源协议会有冲突,所以我就想到扩展自己的集合类,但是在互联网上并没有相关的信息,我在阅读了hibernate3.1的源代码之后找到了解决方案。 以下是具体实现和我的解决问题的过程: 当时想到思路之后没有办法入手,看了一下文档发现文档中并没有详细的说明,只有在一个不起眼的地方表明set节点有collectiontype这个attribute,也没有说这个collectiontype是做什么用的。报着试试的心理,我觉得应该从这个collectiontype入手,于是想到要实现自己的集合类就应该先看看hibernate源代码中PersistentSet相关代码,阅读后发现,hibernate返回什么集合类型是由对应的type类决定的,拿SetType来说 public class SetType extends CollectionType {
public SetType(String role, String propertyRef, boolean isEmbeddedInXML) {
super(role, propertyRef, isEmbeddedInXML);
}
public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key) {
if ( session.getEntityMode()==EntityMode.DOM4J ) {
return new PersistentElementHolder(session, persister, key);
}
else {
return new PersistentSet(session);
}//type类决定返回的集合类
}
public Class getReturnedClass() {
return java.util.Set.class;
}
public PersistentCollection wrap(SessionImplementor session, Object collection) {
if ( session.getEntityMode()==EntityMode.DOM4J ) {
return new PersistentElementHolder( session, (Element) collection );
}
else {
return new PersistentSet( session, (java.util.Set) collection );//type类决定返回的集合类
}
}
public Object instantiate() {
//TODO: Might need to be a LinkedHashSet!!!!!!
return new HashSet();
}
}
由此可以看出要返回什么集合类型确实是由对应的type类决定的,那么就是说要实现自己的集合类必须要搞清楚collectiontype的用法,也就是说必须要先处理我自己的collectiontype,而不是我自己的PersistentSet类,既然是type类,那我想就应该查看org.hibernate.type这个package里的类,看着看着先找到的是一个CustomCollectionType类: public class CustomCollectionType extends CollectionType {
private final UserCollectionType userType;
public CustomCollectionType(Class userTypeClass, String role, String foreignKeyPropertyName, boolean isEmbeddedInXML) {
super(role, foreignKeyPropertyName, isEmbeddedInXML);
if ( !UserCollectionType.class.isAssignableFrom(userTypeClass) ) {
throw new MappingException( "Custom type does not implement UserCollectionType: " + userTypeClass.getName() );
}//也就是说要实现自己的type类就要实现usercollectiontype这个接口,看到这里,思路基本上就确定了。
try {
userType = (UserCollectionType) userTypeClass.newInstance();
}
catch (InstantiationException ie) {
throw new MappingException( "Cannot instantiate custom type: " + userTypeClass.getName() );
}
catch (IllegalAccessException iae) {
throw new MappingException( "IllegalAccessException trying to instantiate custom type: " + userTypeClass.getName() );
}
}
public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister, Serializable key)
throws HibernateException {
return userType.instantiate(session, persister);
}
public PersistentCollection wrap(SessionImplementor session, Object collection) {
return userType.wrap(session, collection);
}
public Class getReturnedClass() {
return userType.instantiate().getClass();
}
public Object instantiate() {
return userType.instantiate();
}
public Iterator getElementsIterator(Object collection) {
return userType.getElementsIterator(collection);
}
public boolean contains(Object collection, Object entity, SessionImplementor session) {
return userType.contains(collection, entity);
}
public Object indexOf(Object collection, Object entity) {
return userType.indexOf(collection, entity);
}
public Object replaceElements(Object original, Object target, Object owner, Map copyCache, SessionImplementor session)
throws HibernateException {
CollectionPersister cp = session.getFactory().getCollectionPersister( getRole() );
return userType.replaceElements(original, target, cp, owner, copyCache, session);
}
}
发现要实现自己collectiontype必须要实现UserCollectionType这个接口(以上hibernate源代码中抛出的异常告诉我们实现自己的collectiontype必须要实现这个接口), 下面的就是UserCollectionType这个接口,我们只需要模范SetType来实现这个接口就可以了
/**
* A custom type for mapping user-written classes that implement <tt>PersistentCollection</tt>
*
* @see org.hibernate.collection.PersistentCollection
* @author Gavin King
*/
public interface UserCollectionType {
/**
* Instantiate an uninitialized instance of the collection wrapper
*/
public PersistentCollection instantiate(SessionImplementor session, CollectionPersister persister)
throws HibernateException;
/**
* Wrap an instance of a collection
*/
public PersistentCollection wrap(SessionImplementor session, Object collection);
/**
* Return an iterator over the elements of this collection - the passed collection
* instance may or may not be a wrapper
*/
public Iterator getElementsIterator(Object collection);
/**
* Optional operation. Does the collection contain the entity instance?
*/
public boolean contains(Object collection, Object entity);
/**
* Optional operation. Return the index of the entity in the collection.
*/
public Object indexOf(Object collection, Object entity);
/**
* Replace the elements of a collection with the elements of another collection
*/
public Object replaceElements(
Object original,
Object target,
CollectionPersister persister,
Object owner,
Map copyCache,
SessionImplementor session)
throws HibernateException;
/**
* Instantiate an empty instance of the "underlying" collection (not a wrapper)
*/
public Object instantiate();
}看到这里开始思路就步上了正轨。大家也都知道怎么做了,开始代码部分吧
步骤1:实现自己的type类 /**
*
* @author 张荣华
* 转载请注明出处
*/
public class AhuaxuanPersistentSetType implements UserCollectionType {
public PersistentCollection instantiate(SessionImplementor arg0,
CollectionPersister arg1) throws HibernateException {
return new AhuaxuanPersistentSet(arg0);
}//这个方法也必须返回我们自己的集合类
public PersistentCollection wrap(SessionImplementor arg0, Object arg1) {
if (arg0.getEntityMode() == EntityMode.DOM4J) {
return new PersistentElementHolder(arg0, (Element) arg1);
} else {
return new AhuaxuanPersistentSet(arg0, (Set) arg1);
}//这个方法也必须返回我们自己的集合类
}//这个方法是最重要的,告诉hibernate我们是返回什么样的具体类型,这里我们指定的是自己的集合类,之所以这样写是因为hibernate自己的type类是这样实现的
//而其他需要实现的方法是拷自hibernate自己的type类,基本可以忽略
}
步骤2:创建自己的集合类: public class AhuaxuanPersistentSet extends PersistentSet {
//这个类其实是继承自hibernate自己的PersistentSet,因为我们只需要下面这个//serialVersionUID而已
/**
*
* @author 张荣华
* 转载请注明出处
*/
private static final long serialVersionUID = 3821652119009257031L;
public AhuaxuanPersistentSet(SessionImplementor session) {
super(session);
}
public AhuaxuanPersistentSet(SessionImplementor session, Set set) {
super(session, set);
}
public AhuaxuanPersistentSet() {
}
}
步骤3:在set节点的collectiontype的attribute上指定我们的AhuaxuanPersistentSetType类了。 <set collection-type=" AhuaxuanPersistentSetType"
name="aa" inverse="true" cascade="save-update" >
<key>
<column name="aa" precision="10" scale="0"/>
</key>
<one-to-many class="test.User"/>
</set>
这样我们就成功的扩展了hibernate,并可以让我们的collectiontype指定返回我们的集合类,以上从遇到问题到产生想法再到实现一共使用了2个小时,只要思路正确,就离问题的解决不远了。 在分布式环境下使用hibernate是会遇到不少问题的,如果团队中没有精通hibernate的成员,那还是推荐ibatis。 希望这篇文章能够对遇到类似问题的同学有帮助。 作者:张荣华,未经作者同意不得随意转载! 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2007-07-23
很多公司都在用spring+hibernate,可是真正懂的人非常之少,大部分人都是照着写增删改查,经常是出了问题而不自知,导致垃圾项目一个接着一个。要是做的是电信和金融等方面的项目,真让人胆颤心惊啊。
像楼主这样爱研究又愿意分享的人不多了,希望楼主在技术上继续精进,只有你这样的人多了,国内的IT水平才能真正提高啊。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-07-26
fuwang 写道 很多公司都在用spring+hibernate,可是真正懂的人非常之少,大部分人都是照着写增删改查,经常是出了问题而不自知,导致垃圾项目一个接着一个。要是做的是电信和金融等方面的项目,真让人胆颤心惊啊。
像楼主这样爱研究又愿意分享的人不多了,希望楼主在技术上继续精进,只有你这样的人多了,国内的IT水平才能真正提高啊。 谢谢,其实懂spring和hibernate的人还是挺多的,但是不懂的人更多。我估计我只是中级水平还不到。当然也不乏很多人懂了一点皮毛就说自己是精通,这种例子也见过很多了。 国内的IT水平要提高只有靠大家的努力,我觉得只要我们做到以下几点国内的水平一定能提高: 1 少谈大道理,多写好代码 2 不要好高骛远 3 成败在于细节 4 讲究学习方法 5 多实践 软件开发是一门工程学,不是说智商越高就越能做好的,当然智商是基础,动手能力的重要性不比智商低。 |
|
| 返回顶楼 | |
|
最后更新时间:2007-07-31
提交给hibernate组织没?
|
|
| 返回顶楼 | |
|
最后更新时间:2007-09-20
赞一个。
不错的分享。 |
|
| 返回顶楼 | |







