Отображение Dozer для объекта Hibernate в DTO - PullRequest
3 голосов
/ 13 мая 2010

Я пытаюсь использовать 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;
 }}

Итак, я получаю объект User, который содержит PersistentBag с ролями. Я применяю карту Dozer Mapper для этого объекта, чтобы получить объект UserDTO. В результате я получаю объект UserDTO с ArrayList из Role и без ArrayList из RoleDTO, как я хотел.

Я думал, что даже если бы я использовал собственный конвертер, dozer преобразует содержимое моего списка. Это не правильный путь? Если нет, то как преобразовать сущность моего домена в объект dto, заменив постоянные коллекции классическими коллекциями Java?

Спасибо за вашу помощь.

Sylvain.

Ответы [ 4 ]

1 голос
/ 14 мая 2010

Я пытаюсь использовать Dozer для преобразования моего доменного объекта в объекты DTO. Итак, я хочу преобразовать PersistentList, PersistentBag, ... из моей доменной сущности в ArrayList, ... в моих объектах DTO, чтобы избежать проблем с отложенным доступом.

Я получил последнее предложение, но не понимаю, почему вам нужно иметь дело с o.h.c.PersistentBag (и т. Д.), Поскольку этот класс равен a 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>

И выполнить преобразование прежде, чем отделить сущности (это ключ вашей проблемы).

1 голос
/ 13 мая 2010

К сожалению, когда вы регистрируете CustomConverter, вы берете на себя всю ответственность за отображение объекта (коллекции в вашем случае), включая все его содержимое, свойства, элементы и т. Д.

Как я вижу сейчас (я раньше этого не видел, это должна быть какая-то новая функция). Существует возможность использовать интерфейс MapperAware, как описано в конце главы для пользовательских преобразователей типов в Dozer docs . Я думаю, это именно то, что подойдет вашим потребностям.

0 голосов
/ 03 января 2013

Как говорит Паскаль, я не вижу смысла использовать 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;
}

Как я заметил, я использовал Dozer по той же причине, и это работало как шарм.

0 голосов
/ 14 мая 2010

Я также протестировал другое решение без специального конвертера:

<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 в роли RoleDTO в UserDTO, я получаю исключение отложенной инициализации из Hibernate, поскольку роли в User находятся в режиме EAGER.

Итак, я не знаю, как сделать это отображение. Я продолжаю искать способ решить эти проблемы

...