在Hibernate的Jira上,这个两个issue已经放了很久了:
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/
分享到:
相关推荐
自从JDK 1.5引入注解机制后,Hibernate也开始支持使用注解来替代传统的XML配置文件。通过在实体类上添加特定的注解,我们可以告诉Hibernate如何将Java对象映射到数据库中的表。这种方法的优势在于,减少了配置文件的...
9. **Listeners and Interceptors**: Hibernate允许注册监听器或拦截器来处理对象生命周期的各个阶段,例如在对象加载、保存、更新或删除时执行自定义逻辑。 10. **Hibernate Tools**: 提供了诸如逆向工程、生成...
Hibernate4注解主要依赖于Hibernate Annotation库,支持EJB3持久性规范,为Java持久化提供了一种标准化机制。 在Hibernate中使用注解进行配置,仍然需要配置文件cfg.xml,但是它被用来指定哪些类通过注解进行配置。...
* Hibernate Annotation 库需要 Java 5 的支持。 * 需要添加 HibernateAnnotations .jar 文件和 Java 持久性 API。 * 需要使用 AnnotationConfiguration 类来建立会话工厂。 * 需要在 Hibernate 配置文件中声明持久...
7. **映射文件解析**:`org.hibernate.cfg`包包含了Hibernate的配置和映射文件解析器,如`AnnotationConfiguration`和`Configuration`,它们负责读取`hibernate.cfg.xml`和实体类上的注解,生成相应的元模型。...
此外,JDK 5.0的注解还支持元注解,允许自定义注解并为其指定元数据,例如`@Target`和`@Retention`。`@Target`定义了注解可以应用的目标(如类、方法、字段等),而`@Retention`指定了注解的生命周期(源码级、编译...
现代IDEs(如IntelliJ IDEA和Eclipse)通常都支持注解的自动补全和语法高亮,使得编写和维护Hibernate实体类变得更加容易。 - **EJB3标准兼容**:Hibernate注解遵循EJB3标准,这意味着你可以使用EJB3编程模型来...
- Hibernate的`org.hibernate.event`和`org.hibernate.interceptor`包支持事件监听和拦截器机制,允许开发者在特定操作(如插入、更新、删除)前后插入自定义逻辑,增强了框架的可扩展性。 7. **实体状态管理:** ...
- 注解基础配置:使用 `<annotationconfiguration>` 标签定义。 - JPA 基础配置:使用 `<jpaconfiguration>` 标签定义。 - JDBC 反向工程配置:使用 `<jdbcconfiguration>` 标签定义。 4. **Exporters**: - ...
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/> <!-- other properties --> ``` 最后,配置Struts2与Spring的整合,确保Action类可以被Spring管理: ```xml ...
<filter-class>org.hibernate.cfg.AnnotationConfiguration <filter-name>hibernateFilter <url-pattern>/* ``` 3. **测试应用**: - 启动应用服务器,访问项目主页进行测试。 - 确认数据库表是否正确...
`AnnotationConfiguration`或`EnhancedAnnotationConfiguration`可能是其中的一部分,用于处理基于注解的配置。 3. **org.hibernate.boot** 包:这部分涉及Hibernate的启动过程和元数据加载,比如`MetadataSources`...
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/> ``` 2. **事务管理器**:配置HibernateTransactionManager,它是Spring与Hibernate集成时用于管理事务的关键组件。...
- 添加Hibernate 4.3.10的相关库文件(例如:`hibernate-core-4.3.10.Final.jar`等)到自定义库中。 - 对于Hibernate 4.3.10版本,还需要确保项目中包含了对SLF4J的支持。可以访问...
4. 使用SessionFactory:在代码中,通过AnnotationConfiguration或HibernateUtil类加载配置文件并创建SessionFactory。 5. 数据操作:与普通Java工程一致,使用SessionFactory的Session对象进行数据库操作。 在...
Hibernate通过事件监听机制处理对象生命周期的各个阶段,如`PreInsertEvent`、`PostUpdateEvent`等,开发者可以通过实现相应的监听器接口,自定义对象持久化过程的行为。 9. **org.hibernate.criterion package** ...
3. `org.hibernate.cfg`:这里的类主要用于配置和初始化Hibernate环境,如`AnnotationConfiguration`类就是配置Hibernate的入口,它会读取注解并生成相应的映射信息。 4. `org.hibernate.boot.model`和`org....
它允许开发人员将Java对象映射到关系型数据库中的表,并支持面向对象的方法来处理数据库操作,从而简化了对数据库的操作。 #### 重要概念解析 **1. Session** - **作用**: `Session` 是 Hibernate 中的核心接口之...
1. 支持JPA 1.0:Hibernate 3.3.2不仅支持其自身的API,还完全兼容Java Persistence API (JPA),为开发者提供了更多选择。 2. 性能优化:通过改进缓存机制和查询执行效率,提升了整体性能。 3. 更好的类型安全:引入...
- **Configuration/AnnotationConfiguration**: 负责读取和解析配置文件。 - **SessionFactory**: 创建`Session`的工厂,每个应用只需一个。 - **Session**: 数据库交互的主要接口,提供CRUD操作方法,如`save()`、`...