Hibernate对象的Dozer映射到DTO

时间:2010-05-13 11:21:15

标签: java hibernate mapping dto dozer

我尝试使用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对象?

感谢您的帮助。

西尔。

4 个答案:

答案 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,这就像魅力一样。