简体   繁体   中英

Java - Mapping DTOs with Circular Dependencies

Currently settings up classic mappers, converting Entities to DTOs. Some of the entities (and thus DTOs) reference each other (after specific JPA entity definition).

Let's say:

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
}

With such circular dependencies I have to set up mappers like so:

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

One way to easily avoid this is to create a new method in PersonMapper or StateMapper and make it NOT map the persons or states. But I was wondering if there was a known design pattern or a more generic way of doing this?

Thanks

The only way is to construct one side first:

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

Everything else would use some Reference<State> like data structure but I don't think thats worth it. You could also break the circular dependency by removing one side and correlate a Person to its States when needed or store a Map<State, List<Person>> on another level. But I still prefer the approach outlined at the start of my post.

On a side-note: Maybe try datus (disclaimer: I am the author) and see if it fits your other conversion tasks and ease your work :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM