所以这是我的难题。我正在编写一个需要处理旧版本应用程序的工具。我有应用程序的代码,但不能改变任何类。为了从我们的数据库中提取信息,我有一个由Hibernate填充的各种DTO。它使用我们的应用程序版本1.0的数据对象,巧妙地命名为DataObject。以下是DTO课程。
public class MyDTO {
private MyWrapperClass wrapper;
public MyDTO(DataObject data) {
wrapper = new MyWrapperClass(data);
}
}
通过Hibernate查询实例化DTO,如下所示:
select new com.foo.bar.MyDTO(t1.data) from mytable t1
现在,在数据对象之上需要一点逻辑,所以我为它创建了一个包装类。请注意,DTO存储包装类的实例,而不是原始数据对象。
public class MyWrapperClass {
private DataObject data;
public MyWrapperClass(DataObject data) {
this.data = data;
}
public String doSomethingImportant() { ... version-specific logic ... }
}
这很有效,直到我需要处理我们的应用程序的2.0版本。现在两个版本中的DataObject非常相似,但不一样。这导致了MyWrapperClass的不同子类,它们实现了自己特定于版本的doSomethingImportant()。仍然没事。但myDTO如何实例化适当的特定版本的MyWrapperClass? Hibernate反过来实例化MyDTO,所以我不能在Spring中@Autowire依赖它。
我很乐意将MyDTO(以及我的许多其他DTO)重用于该工具的两个版本,而无需复制该类。不要重复自己,等等。我敢肯定,我错过了一个非常简单的模式,这对我们有所帮助。有什么建议吗?
答案 0 :(得分:1)
您可以使用Hibernate Interceptor实现instantiate(String entityName, EntityMode entityMode, Serializable id)
。
在该方法中,您可以将MyWrapperClass传递给数据对象。根据应用程序的版本,包装器将有所不同。拦截器可以设置在会话级别或会话工厂级别。
答案 1 :(得分:0)
我和我的同事尝试了很多选择。我们决定使用Hibernate的文档记录很差的ResultTransformer接口(实际上,Hibernate,缺少文档是可耻的)。尽管使用Transformer迫使我们在MyDTO构造函数中手动解析Object []数组,但这是一个值得权衡的权衡。
在ResultTransformer中,我们通过Spring注入了特定于版本的WrapperFactory。我们更改了查询以允许ResultTransformer实例化MyDTO,瞧!问题解决了。以下是我们修改过的查询和DTO类:
"select t1.data from mytable t1"
public class MyDTO<T> {
private MyWrapperClass wrapper;
public MyDTO(Object[] fields, WrapperFactory<T> wrapperFactory) {
T data = (T) fields[0];
wrapper = wrapperFactory.newWrapper(data);
}
}
根据我对纪尧姆的评论,拦截器并没有像希望的那样工作。大概是因为MyDTO不是一个持久的阶级。
我们还尝试让DTO直接通过单例类访问ApplicationContext,然后从那里获取WrapperFactory。虽然这很有效,但可以预见的是我们的单元测试已经结束,我们取消了这种方法。