论坛首页 Java企业应用论坛

Hibernate user type with Annotation - 话题延续

浏览 3128 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-02-17  
前段时间写了一篇介绍hibernate user type的文章: http://www.iteye.com/topic/214145,很长时间没有看了,最近发现有人回帖说:

downpour 写道
http://www.hibernate.org/272.html

hibernate官方论坛早有实现。还是通用的GenericEnumUserType。不是很明白,为什么碰到问题总是喜欢自己实现,而不去google一下别人早已实现了很多遍并经过实践证明的东西。


本想跟贴继续讨论,可是写着写着发现内容比较多,就干脆开个新贴讨论吧,想知道前因的朋友请去看前一个帖子。

好,下面开始本帖的正式话题:

downpour说的官方实现我也知道,我写这个UserType是出于如下考虑:

1. 当然是为了讲解如何编写自定义的hibernate UserType。
2. 为enum定义通用接口便于编写通用util方法(后面会展开讲)。

首先我得承认,对比我这个实现,官方的GenericEnumUserType覆盖面更广,但是使用的时候也有如下不足之处:

1. 需要处理的parameter太多。针对我这个例子,如果要使用GenericEnumUserType的话,注释就得这么写:
@org.hibernate.annotations.TypeDef(
		name = "status", 
		typeClass = de.besitec.octopus.domain.support.GenericEnumUserType.class, 
						parameters = { 
@org.hibernate.annotations.Parameter(
                name = "enumClass", 
		value = "com.yourpackage.Status"), 
@org.hibernate.annotations.Parameter(
		name = "identifierMethod", 
		value = "getId"),
@org.hibernate.annotations.Parameter(
		name = "valueOfMethod", 
		value = "findEnumById"),
								})

而且status类中的id变量必须为Integer。

对于少量的Enum或者是通用的Enum(注释可以写到package-info.java里面去)还好说。一旦enum的数量一多,使用起来岂不是比我的方案麻烦很多?

2. 性能相对较差。GenericEnumUserType实现里调用的反射方法比我写的这个要多,大家知道调用反射方法要比正常的方法调用慢大概10倍左右,如果系统中enum比较多,全部使用这个UserType的话,应该对性能有一定的影响。这一点只是猜测,具体我没有测试,如果有朋友有兴趣测试的话,请告诉我结果,不过请注意,测试的前提是enum比较多。

3. 持久化enum的特例毕竟有限,我们目前的系统除了要保存老的标识符(int)或者是该enum的描述(String)以外,还没有碰到其他的特例,因此编写两个UserType就足够了。日后同事使用起来也方便,毕竟需要的parameter要少很多。

至于为什么说“为enum定义通用接口便于编写通用helper方法”呢?解释起来要费点唇舌,让我们先回过头来看看status的代码:

public   enum  Status  implements  DescriptionID {

	OPEN(5, "This object is activated"), 
	CLOSED(9, "This object is deactivated");

	private int id;
	private String description;

	private Status(int statusNr, String description) {
		this.id = statusNr;
		this.description = description;
	}

	public String getDescription() {
		return this.description;
	}

	public int getId() {
		return id;
	}

	public static List<Status> getAll() {
	      return Arrays.asList(Status.class.getEnumConstants());
	}

        public static  Status findById(Integer id) {
         for  (Status status : getAll()) {
             if  (id  ==  status.getId()) {
                 return  status;
            }
        }
         return   null ;
    }
 }


注意,在老帖子里getAll()写的不好,这里已经纠正了。

仔细看一下status的代码,我们会发现每一个类似的enum类都必须要写findById()这个方法,里面的逻辑代码是完全一样的,完全可以提出到一个util类中去。如果不定义通用接口的话,就必须要用反射来编写。前面说了,过度使用反射会带来性能问题,因此这里建议使用通用接口。

Okay,针对我们这个例子,EnumUtils可以这么些
public class EnumUtils {

	public static <I extends DescriptionID> I getEnum(Class<I> type, int id) {
		I[] types = type.getEnumConstants();
		for (I t : types) {
			if (t.getId() == id)
				return t;
		}
		throw new AssertionError("unable to map: " + id + " to enum: "
				+ type.getSimpleName());
	}
	
	public static <I extends DescriptionID> I getEnum(Class<I> type, String description) {
		I[] types = type.getEnumConstants();
		for (I t : types) {
			if (StringUtils.equals(t.getDescription(), description))
				return t;
		}
		throw new AssertionError("unable to map: " + description + " to enum: "
				+ type.getSimpleName());
	}

	/**
	 * @param <I>
	 * @param type
	 * @return the enum description list
	 */
	public static <I extends DescriptionID> List<String> getDescriptions(Class<I> type) {
		I[] types = type.getEnumConstants();
		List<String> result = new ArrayList<String>(types.length);
		for (I t : types) {
			result.add(t.getDescription());
		}
		return result;
	}
}

三个方法一次为:
1. 根据所给id返回对应enum实例.
2. 根据所给Description返回对应enum实例.
3. 返回所有enum实例的description.

其他方法大家可以自由发挥。

那个静态的findById()方法仍然可以保留,不过逻辑代码已经全部移出:

	public static Status getEnumById(Integer id) {
		return EnumUtils.getEnum(Status.class, id);
	}
   发表时间:2009-10-18  
这个方法不错!
0 请登录后投票
   发表时间:2009-10-20  
JPA默认提供的@Enumerated注解不能解决这个问题么?

对于枚举类型 我们一般这样写就OK了

@Enumerated(EnumType.STRING)
public SexKey getSex() {
	return sex;
}

public void setSex(SexKey sex) {
	this.sex = sex;
}


难道是我没理解楼主的意思?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics