浏览 3128 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2009-02-17
http://www.iteye.com/topic/214145,很长时间没有看了,最近发现有人回帖说:
前段时间写了一篇介绍hibernate user type的文章: 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); } 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-10-18
这个方法不错!
|
|
返回顶楼 | |
发表时间:2009-10-20
JPA默认提供的@Enumerated注解不能解决这个问题么?
对于枚举类型 我们一般这样写就OK了 @Enumerated(EnumType.STRING) public SexKey getSex() { return sex; } public void setSex(SexKey sex) { this.sex = sex; } 难道是我没理解楼主的意思? |
|
返回顶楼 | |