开发者

Dozer mapping for Hibernate object to 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.addA开发者_开发问答ll(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.


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.


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


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜