java 用于 Hibernate 对象到 DTO 的 Dozer 映射

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2826313/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 23:01:39  来源:igfitidea点击:

Dozer mapping for Hibernate object to DTO

javahibernatemappingdtodozer

提问by sylsau

I try to use Dozer to convert my domain entity to DTO objects. So, I want to convert PersistentList, PersistentBag, ... from my domain entity to ArrayList, ... in my DTO objects to avoid lazy problem.

我尝试使用 Dozer 将我的域实体转换为 DTO 对象。所以,我想将 PersistentList、PersistentBag、...从我的域实体转换为 ArrayList、...在我的 DTO 对象中以避免懒惰问题。

This is an example of two of my domain entity :

这是我的两个域实体的示例:

public class User {
      private Collection<Role> roles;
      ...
}

public class Role {
      private Collection<User> users;
      ...
}

My DTO objects are the same except that class are of types DTO. So, to convert domain to DTO objects, I use the following Dozer mapping :

我的 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 is a Dozer custom converter and that is its code :

BagConverter 是一个推土机自定义转换器,这是它的代码:

  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;
 }}

So, I get a User object that contains a PersistentBag with roles. I apply dozer mapper map on that object to obtain UserDTO object. The result that I obtain is a UserDTO object with a ArrayList of Role and no an ArrayList of RoleDTO like I wished.

因此,我得到了一个包含具有角色的 PersistentBag 的 User 对象。我在该对象上应用推土机映射器地图以获取 UserDTO 对象。我获得的结果是一个 UserDTO 对象,它有一个 Role 的 ArrayList,没有我希望的 RoleDTO 的 ArrayList。

I thought that even if I used custom converter, dozer will convert the content of my list. It's not the right way ? If no, how to do to convert my domain entity to dto object by replacing persitent collections to classic java collections ?

我认为即使我使用自定义转换器,推土机也会转换我的列表内容。这不是正确的方法吗?如果不是,如何通过将持久集合替换为经典 java 集合来将我的域实体转换为 dto 对象?

Thanks for your help.

谢谢你的帮助。

Sylvain.

西尔万。

回答by Grzegorz Oledzki

Unfortunately when you register a CustomConverteryou take the whole responsibility for mapping an object (collection in your case) including all its contents, properties, elements, etc.

不幸的是,当您注册 a 时,CustomConverter您将承担映射对象(在您的情况下为集合)的全部责任,包括其所有内容、属性、元素等。

As I see now (I didn't see it before, it has to be some kind of new feature). There's a possibility to use MapperAwareinterface as described at the end of chapter for Custom Type Converters in Dozer docs. I guess this is exactly what would suite your needs.

正如我现在看到的(我之前没有看到它,它必须是某种新功能)。可以使用Dozer 文档中自定义类型转换器章节MapperAware末尾所述的接口。我想这正是满足您需求的方法。

回答by Pascal Thivent

I try to use Dozer to convert my domain entity to DTO objects. So, I want to convert PersistentList, PersistentBag, ... from my domain entity to ArrayList, ... in my DTO objects to avoid lazy problem.

我尝试使用 Dozer 将我的域实体转换为 DTO 对象。所以,我想将 PersistentList、PersistentBag、...从我的域实体转换为 ArrayList、...在我的 DTO 对象中以避免懒惰问题。

I get the last sentence but I don't understand why you need to deal with o.h.c.PersistentBag(and so on) since this class isa List. Just use something like this:

我明白了最后一句话,但我不明白为什么你需要处理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>

And perform the conversion before to detach entities (that's the key of your problem).

并在分离实体之前执行转换(这是您问题的关键)。

回答by sylsau

I also tested an other solution witout custom converter like that :

我还测试了其他没有自定义转换器的解决方案:

<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>

There is another problem. When Dozer try to convert roles from User to roles of RoleDTO in UserDTO, I get a lazy initialisation exception from Hibernate because roles in User is in EAGER mode.

还有一个问题。当 Dozer 尝试将角色从 User 转换为 UserDTO 中的 RoleDTO 角色时,我从 Hibernate 收到延迟初始化异常,因为 User 中的角色处于 EAGER 模式。

So, I don't know how to do that mapping. I continue to search a way to solve these problems

所以,我不知道如何进行映射。我继续寻找解决这些问题的方法

回答by ThanksForAllTheFish

As Pascal says, I don't get the point of using PersistentBags directly. If in your @Entity POJO you declare your list of roles as a classic java.util.Listthen Hibernate will automatically uses its internal representation. That is also the reason while you cannot use your POJO in the serialization process. To clarify:

正如 Pascal 所说,我不明白直接使用 PersistentBags 的意义。如果在 @Entity POJOjava.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
}

Now, when you want to convert your Entity POJO into the DTO object, you just have to use the mapping suggested by Pascal, aka

现在,当您想将实体 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>

doing the conversion before you close the transaction to avoid the lazy initialization exception, eg:

在关闭事务之前进行转换以避免延迟初始化异常,例如:

@Transactional
public UserDTO getUser(...) {
  User user = dao.getUser(...);
  UserDTO dto = //Place your Dozer conversion here
  return dto;
}

As I small note, I was using Dozer for the same reason and this was working like charm.

正如我注意到的那样,我出于同样的原因使用 Dozer,这很有魅力。