Dozer 将 Hibernate 对象映射到 DTO

发布于 2024-09-01 13:22:41 字数 2151 浏览 6 评论 0原文

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

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

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

因此,我得到一个 User 对象,其中包含具有角色的 PersistentBag。我在该对象上应用推土机映射器映射来获取 UserDTO 对象。我获得的结果是一个 UserDTO 对象,其中包含 Role 的 ArrayList,但没有像我希望的那样具有 RoleDTO 的 ArrayList。

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

感谢您的帮助。

西尔万.

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.

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 :

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

  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.

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 ?

Thanks for your help.

Sylvain.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

想你的星星会说话 2024-09-08 13:22:41

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

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

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

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 MapperAware interface as described at the end of chapter for Custom Type Converters in Dozer docs. I guess this is exactly what would suite your needs.

ゝ杯具 2024-09-08 13:22:41

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

我明白最后一句话,但我不明白为什么你需要处理 ohcPercientBag(等等),因为此类一个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>

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

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.

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 is a List. Just use something like this:

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

唐婉 2024-09-08 13:22:41

我还测试了另一种没有这样的自定义转换器的解决方案:

<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 模式。

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

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.

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

虐人心 2024-09-08 13:22:41

正如 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
}

现在,当您想要将 Entity 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;
}

:请注意,我出于同样的原因使用推土机,这就像魅力一样。

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.List then Hibernate will automatically uses its internal representation. That is also the reason while you cannot use your POJO in the serialization process. To clarify:

@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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文