Java - отображение DTO с циклическими зависимостями - PullRequest
0 голосов
/ 27 мая 2019

В настоящее время настраиваются классические мапперы, конвертирующие сущности в DTO. Некоторые из объектов (и, следовательно, DTO) ссылаются друг на друга (после определения конкретного объекта JPA).

Допустим,

public class Person {
  private String name;
  private List<State> states; // All states with this person
  // Getters & Setters
}

public class State {
  private String name;
  private List<Person> persons; // All persons with this state
   // Getters & Setters
}

При таких циклических зависимостях мне нужно настроить маперы так:

public class PersonMapper {
   public PersonDTO toDTO(Person p) { // not null
     PersonDTO dto = new PersonDTO();
     dto.setName(p.getName());
     dto.setStates(p.States().stream().map(stateMapper::toDTO).collect(Collectors.toList());
     return dto;
   }

public class StateMapper {
   public StateDTO toDTO(State s) { // not null
     StateDTO dto = new StateDTO();
     dto.setName(s.getName()); 
     dto.setPersons(s.getPersons().stream().map(personMapper::toDTO).collect(Collectors.toList());
     return dto;
   }

Один из способов легко избежать этого - создать новый метод в PersonMapper или StateMapper и сделать так, чтобы он НЕ отображал людей или состояния. Но мне было интересно, существует ли известный шаблон проектирования или более общий способ сделать это?

Спасибо

1 Ответ

0 голосов
/ 29 мая 2019

Единственный способ - сначала построить одну сторону:

public class PersonMapper {
   public PersonDTO toDTO(Person p) { // not null
     PersonDTO dto = new PersonDTO();
     dto.setName(p.getName());
     dto.setStates(new ArrayList<>());
     states.forEach(state -> state.getPersons().add(dto)) //todo: uniqueness check
     return dto;
   }
}

public class StateMapper {
   //todo: maybe Person.name is better than the whole Person object in the map
   public StateDTO toDTO(State s, Map<Person, PersonDTO> personMapping) { 
     StateDTO dto = new StateDTO();
     dto.setName(s.getName()); 

     List<PersonDTO> persons = s.getPersons().stream().map(personMapping::get)
                               .collect(Collectors.toList();
     persons.forEach(p -> p.getStates().add(dto)) //todo: uniqueness check for states or use a set
     dto.setPersons(persons);

     return dto;
  }
}

Все остальное будет использовать некоторую Reference<State> структуру данных, но я не думаю, что это того стоит. Вы также можете разорвать круговую зависимость, удалив одну сторону и сопоставив Person с States, когда это необходимо, или сохраняя Map<State, List<Person>> на другом уровне. Но я все же предпочитаю подход, изложенный в начале моего поста.

С другой стороны: возможно, попробуйте datus (заявление об отказе: я автор) и посмотрите, подходит ли оно другим задачам преобразования и облегчит ли вам работу:)

...