浏览 3106 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-12-09
最后修改:2008-12-09
Add annotation support for serCollectionType Add the annotations to map the User Collection Type 但是官方一直不给解决,咋办呢?以前唯一的办法就是不用Annotation,回到hbm文件的时代。 经过我几天的跟踪Hibernate的源代码,终于找到了解决办法,在这里分享给大家。 如果我们有这样的实体 @Entity public class Cat { @Id @GeneratedValue private long id; String name; @ManyToOne @JoinColumn(name = "children") Cat mother; @OneToMany(mappedBy = "mother") QSet<Cat> children = new QHashSet<Cat>(); } public interface QSet<E> extends Set<E> { // my stuff } 直接拿给Hibernate持久,毫无疑问会遇到错误。但是之前用hbm文件的时候,是可以配置的。参见 Hibernate: Custom Collection Types 核心的部分就是一行 <set name="subordinates" collection-type="com.javalobby.tnt.hib.FastSetType"> 这个设置到了Annotation时代,要么是消失了,要么是我鼠目寸光,找不到。结果是,再也不能试用自定义的Collection类型了。那么我们来看看Hibernate报了什么错误吧: 引用 "Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: " 通过跟踪源代码,可以发现。之所以会出现这个错误,是因为Hibernate的反射系统认为QSet这个类型不是Collection。再进一步跟踪,发现只有Set.class, List.class这些才被EJB3ReflectionManager认为是Collection。所以第一步,就是通过继承,让ReflectionManager认为QSet也是Collection。 public class CustomizableEJB3ReflectionManager extends EJB3ReflectionManager { private JavaXTypeConverter xTypeConverter = new NoopJavaXTypeConverter(); @Inject public CustomizableEJB3ReflectionManager(JavaXTypeConverter xTypeConverter) { this.xTypeConverter = xTypeConverter; } @Override public JavaXType toXType(TypeEnvironment context, Type propType) { // do things differently here, to make it aware of QSet PublicJavaXType converted = xTypeConverter.convert(context, propType, this); if (converted != null) { return converted; } return super.toXType(context, propType); } } 这样,我们就可以通过第一步了。但是仍然会出错,这回的错误是session.save的时候Hibernate尝试用自己的包装过的collection来代替你手工new出来的collection的时候出错,Hibernate找不到合适的setter。当然嘛,Hibernate认为类型时Set.class,但是实际类型是QSet.class,显然会出错。 为了解决这个问题,还是要像过去一样通过配置一个UserCollectionType。好在Hibernate的Annotation配置和Hbm配置都是一张皮,肉都是一样,都是Configuration这个对象。通过 private void processValues(AnnotationConfiguration config, ValueProcessor processor) { Iterator classMappings = config.getClassMappings(); while (classMappings.hasNext()) { PersistentClass classMapping = (PersistentClass) classMappings.next(); Iterator properties = classMapping.getPropertyIterator(); while (properties.hasNext()) { Property property = (Property) properties.next(); Value value = property.getValue(); processor.process(value); } } } 我们可以拿到所有映射的类(其实不完全是,还有subclass和component,不过简便起见,略过)的属性的映射类。然后再: public class SetValueProcessor implements ValueProcessor { public void process(Value value) { if (!(value instanceof Set)) { return; } Set set = (Set) value; if (set.getTypeName() != null) { return; } set.setTypeName(QueryableSetType.class.getName()); } } public class QueryableSetType implements UserCollectionType { // ... } 我们就可以把我们定义的UserCollectionType附加上去了。而且这样还有一个好处,不需要在所有使用的地方都去声明UserCollectionType,只需要用代码去遍历一遍Configuration就搞定了。具体的代码参加: http://javaonhorse.googlecode.com/svn/trunk/ 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |