我尝试使用Dozer将我的域实体转换为DTO对象。 所以,我想将PersistentList,PersistentBag,...从我的域实体转换为ArrayList,...在我的DTO对象中,以避免延迟问题。
这是我的两个域实体的示例:
public class User {
private Collection<Role> roles;
...
}
public class Role {
private Collection<User> users;
...
}
我的DTO对象是相同的,除了类是DTO类型。因此,要将域转换为DTO对象,我使用以下Dozer映射:
<configuration>
<custom-converters>
<converter type=com.app.mapper.converter.BagConverter">
<class-a>org.hibernate.collection.PersistentBag</class-a>
<class-b>java.util.List</class-b>
</converter>
</custom-converters>
</configuration>
<mapping>
<class-a>com.app.domain.User</class-a>
<class-b>com.app.dto.UserDTO</class-b>
</mapping>
<mapping>
<class-a>com.app.domain.Role</class-a>
<class-b>com.app.dto.RoleDTO</class-b>
</mapping>
BagConverter是一个Dozer自定义转换器,它的代码是:
public class BagConverter<T> extends DozerConverter<PersistentBag, List>{
public BagConverter() {
super(PersistentBag.class, List.class);
}
public PersistentBag convertFrom(List source, PersistentBag destination) {
PersistentBag listDest = null;
if (source != null) {
if (destination == null) {
listDest = new PersistentBag();
} else {
listDest = destination;
}
listDest.addAll(source);
}
return listDest;
}
public List convertTo(PersistentBag source, List destination) {
List listDest = null;
if (source != null) {
if (destination == null) {
listDest = new ArrayList<T>();
} else {
listDest = destination;
}
if (source.wasInitialized()) {
listDest.addAll(source);
}
}
return listDest;
}}
因此,我得到一个包含带角色的PersistentBag的User对象。我在该对象上应用dozer映射器映射以获取UserDTO对象。我得到的结果是一个带有角色ArrayList的UserDTO对象,而不像我希望的那样没有RoleDTO的ArrayList。
我认为即使我使用自定义转换器,推土机也会转换我的列表内容。这不是正确的方法吗?如果不是,如何通过将persitent集合替换为经典java集合来将我的域实体转换为dto对象?
感谢您的帮助。
西尔。
答案 0 :(得分:1)
不幸的是,当您注册 CustomConverter
时,您将负责映射对象(在您的案例中为集合),包括其所有内容,属性,元素等。
正如我现在所见(我之前没有看过它,它必须是某种新功能)。可以使用chapter for Custom Type Converters in Dozer docs末尾所述的MapperAware
接口。我想这正是满足您需求的原因。
答案 1 :(得分:1)
我尝试使用Dozer将我的域实体转换为DTO对象。所以,我想将PersistentList,PersistentBag,...从我的域实体转换为ArrayList,...在我的DTO对象中,以避免延迟问题。
我得到了最后一句,但我不明白为什么你需要处理o.h.c.PersistentBag
(等等)因为这个类 是List
。只需使用这样的东西:
<mapping>
<class-a>com.myapp.domain.User</class-a>
<class-b>com.myapp.dto.UserDTO</class-b>
<field>
<a>roles</a>
<b>roles</b>
<a-hint>com.myapp.domain.Role</a-hint>
<b-hint>com.myapp.dto.RoleDTO</b-hint>
</field>
</mapping>
在分离实体之前执行转换(这是问题的关键)。
答案 2 :(得分:0)
我还测试了另一个没有自定义转换器的解决方案:
<mapping>
<class-a>com.myapp.domain.User</class-a>
<class-b>com.myapp.dto.UserDTO</class-b>
<field>
<a>roles</a>
<b>roles</b>
<a-hint>com.myapp.domain.Role</a-hint>
<b-hint>com.myapp.dto.RoleDTO</b-hint>
</field>
</mapping>
还有另一个问题。当Dozer尝试将角色从User转换为UserDTO中RoleDTO的角色时,我从Hibernate获得了一个懒惰的初始化异常,因为User中的角色处于EAGER模式。
所以,我不知道如何进行映射。我继续寻找解决这些问题的方法
答案 3 :(得分:0)
正如Pascal所说,我没有直接使用PersistentBags的意义。如果在你的@Entity POJO中你将角色列表声明为经典java.util.List
,那么Hibernate将自动使用其内部表示。这也是您在序列化过程中无法使用POJO的原因。澄清:
@Entity
public class User {
private java.util.List<Role> roles = new java.util.Arraylist<Role>(); //Hibernate doesn't really care about this new Arraylist stuff, it will use its org.hibernate.collection.PersistentList
... //other fields and methods
}
现在,当您想要将实体POJO转换为DTO对象时,您只需使用Pascal建议的映射,即
<mapping>
<class-a>com.myapp.domain.User</class-a>
<class-b>com.myapp.dto.UserDTO</class-b>
<field>
<a>roles</a>
<b>roles</b>
<a-hint>com.myapp.domain.Role</a-hint>
<b-hint>com.myapp.dto.RoleDTO</b-hint>
</field>
</mapping>
在关闭事务之前进行转换以避免延迟初始化异常,例如:
@Transactional
public UserDTO getUser(...) {
User user = dao.getUser(...);
UserDTO dto = //Place your Dozer conversion here
return dto;
}
正如我的小记,我出于同样的原因使用了Dozer,这就像魅力一样。