ModelMapper: рдЧреЛрд▓ рдпрд╛рддреНрд░рд╛

рдЫрд╡рд┐

рдкреНрд░рд╕рд┐рджреНрдз рдХрд╛рд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП, рдмреИрдХреЗрдВрдб рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдбреЗрдЯрд╛ рд╡рд╛рдкрд╕ рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИред рд╕рдмрд╕реЗ рдкреНрд░рд╕рд┐рджреНрдз - рдЖрд╡рд╢реНрдпрдХ рдирд┐рд░реНрднрд░рддрд╛рдПрдВ рдЖрдзрд╛рд░ рд╕реЗ рдЙрд╕ рд░реВрдк рдореЗрдВ рдирд╣реАрдВ рд▓реА рдЬрд╛рддреА рд╣реИрдВ рдЬрд┐рд╕рдореЗрдВ рд╕рд╛рдордиреЗ рд╡рд╛рд▓рд╛ рдЙрдиреНрд╣реЗрдВ рд╕рдордЭ рд╕рдХрддрд╛ рд╣реИред рдпрд╣рд╛рдВ рдЖрдк рдкрд╛рд░реНрд╕рд┐рдВрдЧ рдПрдирдо рдХреЗ рд╕рд╛рде рдХрдард┐рдирд╛рдЗрдпреЛрдВ рдХреЛ рдЬреЛрдбрд╝ рд╕рдХрддреЗ рд╣реИрдВ (рдпрджрд┐ рдПрдирдо рдлрд╝реАрд▓реНрдб рдореЗрдВ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреИрд░рд╛рдореАрдЯрд░ рд╣реИрдВ), рдФрд░ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рдкреНрд░рдХрд╛рд░ рдХреА рдХрд╛рд╕реНрдЯрд┐рдВрдЧ (рдпрд╛ рд╕реНрд╡рдЪрд╛рд▓рд┐рдд рд░реВрдк рд╕реЗ рдЙрдиреНрд╣реЗрдВ рдбрд╛рд▓рдиреЗ рдореЗрдВ рдЕрд╕рдорд░реНрдерддрд╛) рд╕реЗ рдЙрддреНрдкрдиреНрди рд╣реЛрдиреЗ рд╡рд╛рд▓реА рдХрдИ рдЕрдиреНрдп рдХрдард┐рдирд╛рдЗрдпрд╛рдВ рд╣реИрдВред рдЗрд╕рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд┐ рдбреЗрдЯрд╛ рдЯреНрд░рд╛рдВрд╕рдлрд░ рдСрдмреНрдЬреЗрдХреНрдЯ - рдбреАрдЯреАрдУ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ, рдЬреЛ рдкреАрдЫреЗ рдФрд░ рд╕рд╛рдордиреЗ рджреЛрдиреЛрдВ рдХреЗ рд▓рд┐рдП рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИред
рдПрдХ рдЗрдХрд╛рдИ рдХреЛ рдбреАрдЯреАрдУ рдореЗрдВ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдирд╛ рдХрдИ рдЕрд▓рдЧ-рдЕрд▓рдЧ рддрд░реАрдХреЛрдВ рд╕реЗ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдЖрдк рдкреБрд╕реНрддрдХрд╛рд▓рдп рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рдЖрдк рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ (рдпрджрд┐ рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдЫреЛрдЯрд╛ рд╣реИ) рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рд╕реЗ рдПрдХ рд╕рд╛рде рд░рдЦрд╛ рдЬрд╛рдП:

@Component public class ItemMapperImpl implements ItemMapper { private final OrderRepository orderRepository; @Autowired public ItemMapperImpl(OrderRepository orderRepository) { this.orderRepository = orderRepository; } @Override public Item toEntity(ItemDto dto) { return new Item( dto.getId(), obtainOrder(dto.getOrderId()), dto.getArticle(), dto.getName(), dto.getDisplayName(), dto.getWeight(), dto.getCost(), dto.getEstimatedCost(), dto.getQuantity(), dto.getBarcode(), dto.getType() ); } @Override public ItemDto toDto(Item item) { return new ItemDto( item.getId(), obtainOrderId(item), item.getArticle(), item.getName(), item.getDisplayName(), item.getWeight(), item.getCost(), item.getEstimatedCost(), item.getQuantity(), item.getBarcode(), item.getType() ); } private Long obtainOrderId(Item item) { return Objects.nonNull(item.getOrder()) ? item.getOrder().getId() : null; } private Order obtainOrder(Long orderId) { return Objects.nonNull(orderId) ? orderRepository.findById(orderId).orElse(null) : null; } } 

рдЗрд╕ рддрд░рд╣ рдХреЗ рд╕реНрд╡-рд▓рд┐рдЦрд┐рдд рдореИрдкрд░ рдХреЗ рд╕реНрдкрд╖реНрдЯ рдиреБрдХрд╕рд╛рди рд╣реИрдВ:

  1. рдкреИрдорд╛рдирд╛ рдирд╣реАрдВ рд╣реИред
  2. рд╕рдмрд╕реЗ рдорд╣рддреНрд╡рд╣реАрди рдХреНрд╖реЗрддреНрд░ рдХреЛ рдЬреЛрдбрд╝рдиреЗ / рд╣рдЯрд╛рдиреЗ рдкрд░, рдЖрдкрдХреЛ рдореИрдкрд░ рдХреЛ рд╕рдВрдкрд╛рджрд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рдЗрд╕рд▓рд┐рдП, рдореИрдкрд░ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╕рд╣реА рд╕рдорд╛рдзрд╛рди рд╣реИред рдореИрдВ рдореЙрдбрд▓рдореИрдкрд░ рдФрд░ рдореИрдкрд╕реНрдЯреНрд░реИрдХ рдЬрд╛рдирддрд╛ рд╣реВрдВред рдЬрдм рд╕реЗ рдореИрдВрдиреЗ рдореЙрдбрд▓рдореИрдкрд░ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд┐рдпрд╛ рд╣реИ, рдореИрдВ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░реВрдВрдЧрд╛, рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдк, рдореЗрд░реЗ рдкрд╛рдардХ, рдореИрдкрд╕реНрдЯреНрд░реИрдХ рд╕реЗ рдЕрдЪреНрдЫреА рддрд░рд╣ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИрдВ рдФрд░ рдЗрд╕рдХреЗ рдЖрд╡реЗрджрди рдХреА рд╕рднреА рдмрд╛рд░реАрдХрд┐рдпреЛрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрддрд╛ рд╕рдХрддреЗ рд╣реИрдВ, рддреЛ рдХреГрдкрдпрд╛ рдЗрд╕рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдПрдХ рд▓реЗрдЦ рд▓рд┐рдЦреЗрдВ, рдФрд░ рдореИрдВ рдЗрд╕реЗ рд▓рд┐рдЦрдиреЗ рд╡рд╛рд▓рд╛ рдкрд╣рд▓рд╛ рд╡реНрдпрдХреНрддрд┐ рдмрдиреВрдБрдЧрд╛ (рдпрд╣ рд▓рд╛рдЗрдмреНрд░реЗрд░реА рднреА рдмрд╣реБрдд рд╣реИ рджрд┐рд▓рдЪрд╕реНрдк рд╣реИ, рд▓реЗрдХрд┐рди рдЕрднреА рддрдХ рдЗрд╕рдореЗрдВ рдкреНрд░рд╡реЗрд╢ рдХрд░рдиреЗ рдХрд╛ рд╕рдордп рдирд╣реАрдВ рд╣реИ)ред

рддреЛ рдореЙрдбрд▓рдкрд╛рд╡рд░ред

рдореИрдВ рддреБрд░рдВрдд рдпрд╣ рдХрд╣рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдХрд┐ рдЕрдЧрд░ рдЖрдкрдХреЗ рд▓рд┐рдП рдХреБрдЫ рд╕реНрдкрд╖реНрдЯ рдирд╣реАрдВ рд╣реИ, рддреЛ рдЖрдк рдХрд╛рдо рдХрд░ рд░рд╣реЗ рдкрд░реАрдХреНрд╖рдг рдХреЗ рд╕рд╛рде рд╕рдорд╛рдкреНрдд рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ, рд▓реЗрдЦ рдХреЗ рдЕрдВрдд рдореЗрдВ рдПрдХ рд▓рд┐рдВрдХред

рдкрд╣рд▓рд╛ рдХрджрдо, рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ, рдПрдХ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдЬреЛрдбрд╝рдирд╛ рд╣реИред рдореИрдВ рдЧреНрд░реЗрдбреЗрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реВрдВ, рд▓реЗрдХрд┐рди рдЖрдкрдХреЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдорд╛рд╡реЗрди рдкреНрд░реЛрдЬреЗрдХреНрдЯ рдкрд░ рдирд┐рд░реНрднрд░рддрд╛ рдЬреЛрдбрд╝рдирд╛ рдЖрд╕рд╛рди рд╣реИред

 compile group: 'org.modelmapper', name: 'modelmapper', version: '2.3.2' 

рдпрд╣ рдореИрдкрд░ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рдЕрдЧрд▓рд╛, рд╣рдореЗрдВ рдПрдХ рдмрд┐рди рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

 @Bean public ModelMapper modelMapper() { ModelMapper mapper = new ModelMapper(); mapper.getConfiguration() .setMatchingStrategy(MatchingStrategies.STRICT) .setFieldMatchingEnabled(true) .setSkipNullEnabled(true) .setFieldAccessLevel(PRIVATE); return mapper; } 

рдЖрдорддреМрд░ рдкрд░ рдпрд╣ рдХреЗрд╡рд▓ рдирдП ModelMapper рдХреЛ рд╡рд╛рдкрд╕ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкрд░реНрдпрд╛рдкреНрдд рд╣реИ, рд▓реЗрдХрд┐рди рдпрд╣ рд╣рдорд╛рд░реА рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдореИрдкрд░ рдХреЛ рдХреЙрдиреНрдлрд╝рд┐рдЧрд░ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рд╢рд╛рдирджрд╛рд░ рдирд╣реАрдВ рд╣реЛрдЧрд╛ред рдореИрдВрдиреЗ рдПрдХ рд╕рдЦреНрдд рдорд┐рд▓рд╛рди рд░рдгрдиреАрддрд┐ рд╕реЗрдЯ рдХреА, рдлрд╝реАрд▓реНрдб рдореИрдкрд┐рдВрдЧ рд╕рдХреНрд╖рдо рдХрд┐рдпрд╛, рдирд▓ рдлрд╝реАрд▓реНрдб рдХреЛ рдЫреЛрдбрд╝ рджрд┐рдпрд╛, рдФрд░ рдЦреЗрддреЛрдВ рддрдХ рдирд┐рдЬреА рд╕реНрддрд░ рдХреА рдкрд╣реБрдВрдЪ рд╕реНрдерд╛рдкрд┐рдд рдХреАред

рдЕрдЧрд▓рд╛, рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЗрдХрд╛рдИ рд╕рдВрд░рдЪрдирд╛ рдмрдирд╛рдПрдВред рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рдпреВрдирд┐рдХреЙрд░реНрди рд╣реЛрдЧрд╛, рдЬрд┐рд╕рдореЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдбреНрд░реЙрдЗрдб рдЕрдзреАрдирд╕реНрде рд╣реЛрдВрдЧреЗ, рдФрд░ рдкреНрд░рддреНрдпреЗрдХ рдбреНрд░реЙрдЗрдб рдореЗрдВ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рд╕рдВрдЦреНрдпрд╛ рдореЗрдВ рдХрдкрдХреЗрдХ рд╣реЛрдВрдЧреЗред

рддрдереНрдп
рдореВрд▓ рдЕрднрд┐рднрд╛рд╡рдХ:

 @MappedSuperclass @Setter @EqualsAndHashCode @NoArgsConstructor @AllArgsConstructor public abstract class AbstractEntity implements Serializable { Long id; LocalDateTime created; LocalDateTime updated; @Id @GeneratedValue public Long getId() { return id; } @Column(name = "created", updatable = false) public LocalDateTime getCreated() { return created; } @Column(name = "updated", insertable = false) public LocalDateTime getUpdated() { return updated; } @PrePersist public void toCreate() { setCreated(LocalDateTime.now()); } @PreUpdate public void toUpdate() { setUpdated(LocalDateTime.now()); } } 

рдпреВрдирд┐рдХреЙрд░реНрди:

 @Entity @Table(name = "unicorns") @EqualsAndHashCode(callSuper = false) @Setter @AllArgsConstructor @NoArgsConstructor public class Unicorn extends AbstractEntity { private String name; private List<Droid> droids; private Color color; public Unicorn(String name, Color color) { this.name = name; this.color = color; } @Column(name = "name") public String getName() { return name; } @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "unicorn") public List<Droid> getDroids() { return droids; } @Column(name = "color") public Color getColor() { return color; } } 

Droid:

 @Setter @EqualsAndHashCode(callSuper = false) @Entity @Table(name = "droids") @AllArgsConstructor @NoArgsConstructor public class Droid extends AbstractEntity { private String name; private Unicorn unicorn; private List<Cupcake> cupcakes; private Boolean alive; public Droid(String name, Unicorn unicorn, Boolean alive) { this.name = name; this.unicorn = unicorn; this.alive = alive; } public Droid(String name, Boolean alive) { this.name = name; this.alive = alive; } @Column(name = "name") public String getName() { return name; } @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "unicorn_id") public Unicorn getUnicorn() { return unicorn; } @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "droid") public List<Cupcake> getCupcakes() { return cupcakes; } @Column(name = "alive") public Boolean getAlive() { return alive; } } 

рдХрдк рдХреЗрдХ:

 @Entity @Table(name = "cupcakes") @Setter @EqualsAndHashCode(callSuper = false) @AllArgsConstructor @NoArgsConstructor public class Cupcake extends AbstractEntity { private Filling filling; private Droid droid; @Column(name = "filling") public Filling getFilling() { return filling; } @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "droid_id") public Droid getDroid() { return droid; } public Cupcake(Filling filling) { this.filling = filling; } } 


рд╣рдо рдЗрди рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЛ рдбреАрдЯреАрдУ рдореЗрдВ рдмрджрд▓ рджреЗрдВрдЧреЗред рдПрдХ рдЗрдХрд╛рдИ рд╕реЗ рдбреАрдЯреАрдУ рддрдХ рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдкрд░рд┐рд╡рд░реНрддрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдо рд╕реЗ рдХрдо рджреЛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реИрдВред рдПрдХ рдХрд╛ рддрд╛рддреНрдкрд░реНрдп рдЗрдХрд╛рдИ рдХреЗ рдмрдЬрд╛рдп рдХреЗрд╡рд▓ рдЖрдИрдбреА рдХреЛ рдмрдЪрд╛рдиреЗ рд╕реЗ рд╣реИ, рд▓реЗрдХрд┐рди рдлрд┐рд░ рдирд┐рд░реНрднрд░рддрд╛ рд╕реЗ рдкреНрд░рддреНрдпреЗрдХ рдЗрдХрд╛рдИ, рдпрджрд┐ рдЖрд╡рд╢реНрдпрдХ рд╣реЛ, рддреЛ рд╣рдо рдЕрддрд┐рд░рд┐рдХреНрдд рд░реВрдк рд╕реЗ рдЖрдИрдбреА рдкрд░ рдЦреАрдВрдЪ рд▓реЗрдВрдЧреЗред рджреВрд╕рд░реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдореЗрдВ рдбреАрдЯреАрдУ рдХреЛ рдирд┐рд░реНрднрд░ рд░рдЦрдирд╛ рд╢рд╛рдорд┐рд▓ рд╣реИред рдЗрд╕рд▓рд┐рдП, рдкрд╣рд▓реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдореЗрдВ, рд╣рдо рд▓рд┐рд╕реНрдЯ рдбреНрд░реЙрдЗрдбреНрд╕ рдХреЛ рд▓рд┐рд╕реНрдЯ рдбреНрд░реЙрдЗрдбреНрд╕ рдореЗрдВ рдмрджрд▓реЗрдВрдЧреЗ (рд╣рдо рдХреЗрд╡рд▓ рдирдИ рд╕реВрдЪреА рдореЗрдВ рдЖрдИрдбреА рд╕реНрдЯреЛрд░ рдХрд░рддреЗ рд╣реИрдВ), рдФрд░ рджреВрд╕рд░реЗ рджреГрд╖реНрдЯрд┐рдХреЛрдг рдореЗрдВ, рд╣рдо рд▓рд┐рд╕реНрдЯ рдбреНрд░реЙрдЗрдбреНрд╕ рдореЗрдВ рдмрдЪрдд рдХрд░реЗрдВрдЧреЗред

рдбреАрдЯреАрдУ
рдореВрд▓ рдЕрднрд┐рднрд╛рд╡рдХ:

 @Data public abstract class AbstractDto implements Serializable { private Long id; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS") LocalDateTime created; @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss.SSS") LocalDateTime updated; } 

UnicornDto:

 @EqualsAndHashCode(callSuper = true) @Data @NoArgsConstructor @AllArgsConstructor public class UnicornDto extends AbstractDto { private String name; private List<DroidDto> droids; private String color; } 

DroidDto:

 @EqualsAndHashCode(callSuper = true) @Data @NoArgsConstructor @AllArgsConstructor public class DroidDto extends AbstractDto { private String name; private List<CupcakeDto> cupcakes; private UnicornDto unicorn; private Boolean alive; } 

CupcakeDto:

 @EqualsAndHashCode(callSuper = true) @Data @NoArgsConstructor @AllArgsConstructor public class CupcakeDto extends AbstractDto { private String filling; private DroidDto droid; } 


рд╣рдорд╛рд░реА рдЖрд╡рд╢реНрдпрдХрддрд╛рдУрдВ рдХреЗ рд▓рд┐рдП рдореИрдкрд░ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдореЗрдВ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рд░реИрдкрд░ рд╡рд░реНрдЧ рдмрдирд╛рдиреЗ рдФрд░ рдорд╛рдирдЪрд┐рддреНрд░рдг рд╕рдВрдЧреНрд░рд╣ рдХреЗ рд▓рд┐рдП рддрд░реНрдХ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рдПрдХ рдШрдЯрдХ рд╡рд░реНрдЧ UnicornMapper рдмрдирд╛рддреЗ рд╣реИрдВ, рд╡рд╣рд╛рдВ рд╣рдорд╛рд░реЗ рдореИрдкрд░ рдХреЛ рдСрдЯреЛ-рдореИрдк рдХрд░рддреЗ рд╣реИрдВ рдФрд░ рд╣рдорд╛рд░реЗ рджреНрд╡рд╛рд░рд╛ рдЖрд╡рд╢реНрдпрдХ рддрд░реАрдХреЛрдВ рдХреЛ рдлрд┐рд░ рд╕реЗ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред

рд░реИрдкрд░ рдХреНрд▓рд╛рд╕ рдХрд╛ рд╕рдмрд╕реЗ рд╕рд░рд▓ рд╕рдВрд╕реНрдХрд░рдг рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

 @Component public class UnicornMapper { @Autowired private ModelMapper mapper; @Override public Unicorn toEntity(UnicornDto dto) { return Objects.isNull(dto) ? null : mapper.map(dto, Unicorn.class); } @Override public UnicornDto toDto(Unicorn entity) { return Objects.isNull(entity) ? null : mapper.map(entity, UnicornDto.class); } } 

рдЕрдм рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЕрдкрдиреЗ рдордкреЗрд░ рдХреЛ рдХреБрдЫ рд╕реЗрд╡рд╛ рдореЗрдВ рд╢рд╛рдорд┐рд▓ рдХрд░рдирд╛ рдФрд░ рдЯреВрдбреВ рдФрд░ рддрд╛рддреНрдХрд╛рд▓рд┐рдХ рддрд░реАрдХреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдирд╛ рдкрд░реНрдпрд╛рдкреНрдд рд╣реИред рдореИрдкрд░ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдкрд╛рдИ рдЬрд╛рдиреЗ рд╡рд╛рд▓реА рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЛ DTO, DTO - рд╕рдВрд╕реНрдерд╛рдУрдВ рдореЗрдВ рдмрджрд▓ рджреЗрдЧрд╛ред

 @Service public class UnicornServiceImpl implements UnicornService { private final UnicornRepository repository; private final UnicornMapper mapper; @Autowired public UnicornServiceImpl(UnicornRepository repository, UnicornMapper mapper) { this.repository = repository; this.mapper = mapper; } @Override public UnicornDto save(UnicornDto dto) { return mapper.toDto(repository.save(mapper.toEntity(dto))); } @Override public UnicornDto get(Long id) { return mapper.toDto(repository.getOne(id)); } } 

рд▓реЗрдХрд┐рди рдЕрдЧрд░ рд╣рдо рдЗрд╕ рддрд░рд╣ рд╕реЗ рдХреБрдЫ рдмрджрд▓рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдлрд┐рд░ рдХреЙрд▓ рдХрд░рддреЗ рд╣реИрдВ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, toString, рддреЛ рд╣рдореЗрдВ рдПрдХ StackOverflowException рдорд┐рд▓реЗрдЧреА, рдФрд░ рдпрд╣рд╛рдБ рдХреНрдпреЛрдВ: UnicornDto рдореЗрдВ DroidDto рд╕реВрдЪреА рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ UnornornDto рд╢рд╛рдорд┐рд▓ рд╣реИ, рдЬрд┐рд╕рдореЗрдВ DroidDto рд╢рд╛рдорд┐рд▓ рд╣реИ, рдФрд░ рдЗрд╕реА рдХреНрд╖рдг рддрдХред рдЬрдм рддрдХ рд╕реНрдЯреИрдХ рдореЗрдореЛрд░реА рдмрд╛рд╣рд░ рдирд╣реАрдВ рдирд┐рдХрд▓ рдЬрд╛рддреАред рдЗрд╕рд▓рд┐рдП, рд╡реНрдпреБрддреНрдХреНрд░рдо рдирд┐рд░реНрднрд░рддрд╛ рдХреЗ рд▓рд┐рдП, рдореИрдВ рдЖрдорддреМрд░ рдкрд░ рдпреВрдирд┐рдХреЙрд░реНрдирдбреЙрдХ рдпреВрдирд┐рдХреЙрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛, рд▓реЗрдХрд┐рди рд▓реЙрдиреНрдЧ рдпреВрдирд┐рдХреЙрд░реНрди рдХрд░рддрд╛ рд╣реВрдВред рдЗрд╕ рддрд░рд╣, рд╣рдо рдпреВрдирд┐рдХреЙрд░реНрди рдХреЗ рд╕рдВрдкрд░реНрдХ рдореЗрдВ рд░рд╣рддреЗ рд╣реИрдВ, рд▓реЗрдХрд┐рди рдЪрдХреНрд░реАрдп рдирд┐рд░реНрднрд░рддрд╛ рдХреЛ рдХрд╛рдЯ рджреЗрддреЗ рд╣реИрдВред рдЪрд▓реЛ рд╣рдорд╛рд░реЗ рдбреАрдЯреАрдУ рдХреЛ рдареАрдХ рдХрд░рддреЗ рд╣реИрдВ рддрд╛рдХрд┐ рд░рд┐рд╡рд░реНрд╕ рдбреАрдЯреАрдУ рдХреЗ рдмрдЬрд╛рдп, рд╡реЗ рдЕрдкрдиреА рдирд┐рд░реНрднрд░рддрд╛ рдХреА рдЖрдИрдбреА рд╕реНрдЯреЛрд░ рдХрд░реЗрдВред

 @EqualsAndHashCode(callSuper = true) @Data @NoArgsConstructor @AllArgsConstructor public class DroidDto extends AbstractDto { ... //private UnicornDto unicorn; private Long unicornId; ... } 

рдФрд░ рдЗрд╕реА рддрд░рд╣ред

рд▓реЗрдХрд┐рди рдЕрдм, рдЕрдЧрд░ рд╣рдо DroidMapper рдХрд╣рддреЗ рд╣реИрдВ, рддреЛ рд╣рдореЗрдВ unicornId == null рдорд┐рд▓рддрд╛ рд╣реИред рдРрд╕рд╛ рдЗрд╕рд▓рд┐рдП рд╣реИ рдХреНрдпреЛрдВрдХрд┐ ModelMapper рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдирд╣реАрдВ рдХрд░ рд╕рдХрддрд╛ рд╣реИ рдХрд┐ рд▓реЙрдиреНрдЧ рдХреНрдпрд╛ рд╣реИред рдФрд░ рд╕рд┐рд░реНрдл рдЙрд╕реЗ рдкрд░реЗрд╢рд╛рди рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред рдФрд░ рд╣рдореЗрдВ рдЖрдИрдбреА рдореЗрдВ рд╕рдВрд╕реНрдерд╛рдУрдВ рдХреЛ рдореИрдк рдХрд░рдиреЗ рдХреЗ рддрд░реАрдХреЗ рд╕рд┐рдЦрд╛рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдореИрдкрд░реНрд╕ рдХреЛ рддреИрдпрд╛рд░ рдХрд░рдирд╛ рд╣реЛрдЧрд╛ред

рд╣рдореЗрдВ рдпрд╛рдж рд╣реИ рдХрд┐ рдЗрд╕рдХреЗ рдЖрд░рдВрдн рдХреЗ рдмрд╛рдж рдкреНрд░рддреНрдпреЗрдХ рдмрд┐рди рдХреЗ рд╕рд╛рде, рдЖрдк рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рдХрд╛рдо рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред

  @PostConstruct public void setupMapper() { mapper.createTypeMap(Droid.class, DroidDto.class) .addMappings(m -> m.skip(DroidDto::setUnicornId)).setPostConverter(toDtoConverter()); mapper.createTypeMap(DroidDto.class, Droid.class) .addMappings(m -> m.skip(Droid::setUnicorn)).setPostConverter(toEntityConverter()); } 

@PostConstruct рдореЗрдВ рд╣рдо рдЙрди рдирд┐рдпрдореЛрдВ рдХреЛ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВрдЧреЗ рдЬрд┐рдирдореЗрдВ рд╣рдо рдЗрдВрдЧрд┐рдд рдХрд░рддреЗ рд╣реИрдВ рдХрд┐ рдореИрдкрд░ рдХреЛ рдХрд┐рди рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рд╕реНрдкрд░реНрд╢ рдирд╣реАрдВ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдП, рдХреНрдпреЛрдВрдХрд┐ рдЙрдирдХреЗ рд▓рд┐рдП рд╣рдо рдЕрдкрдиреЗ рджрдо рдкрд░ рддрд░реНрдХ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВрдЧреЗред рд╣рдорд╛рд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдпрд╣ рдбреАрдЯреАрдУ рдореЗрдВ рдпреВрдирд┐рдХреЙрд░реНрди рдХреА рдкрд░рд┐рднрд╛рд╖рд╛ рд╣реИ, рдФрд░ рд╕рд╛рд░ рдореЗрдВ рдпреВрдирд┐рдХреЙрд░реНрди рдХреА рдкрд░рд┐рднрд╛рд╖рд╛ (рдЪреВрдВрдХрд┐ рдореИрдкрд░ рдХреЛ рднреА рдкрддрд╛ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд▓реЙрдиреНрдЧ рдпреВрдирд┐рдХреЙрд░реНрди рдХреЗ рд╕рд╛рде рдХреНрдпрд╛ рдХрд░рдирд╛ рд╣реИ)ред

TypeMap - рдпрд╣ рд╡рд╣ рдирд┐рдпрдо рд╣реИ рдЬрд┐рд╕рдореЗрдВ рд╣рдо рдорд╛рдирдЪрд┐рддреНрд░рдг рдХреА рд╕рднреА рдмрд╛рд░реАрдХрд┐рдпреЛрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рдФрд░ рдХрдирд╡рд░реНрдЯрд░ рдХреЛ рднреА рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рд╣рдордиреЗ рдмрддрд╛рдпрд╛ рдХрд┐ Droid рд╕реЗ DroidDto рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо setUnicornId рдХреЛ рдЫреЛрдбрд╝рддреЗ рд╣реИрдВ, рдФрд░ рд░рд┐рд╡рд░реНрд╕ рд░реВрдкрд╛рдВрддрд░рдг рдореЗрдВ, рд╣рдо setUnicorn рдкрд╛рд╕ рдХрд░рддреЗ рд╣реИрдВред рд╣рдо рд╕рднреА UnicornDto рдХреЗ рд▓рд┐рдП toDtoConverter () рдХрдиреНрд╡рд░реНрдЯрд░ рдФрд░ Unicorn рдХреЗ рд▓рд┐рдП inEntityConverter () рдореЗрдВ рдХрдирд╡рд░реНрдЯ рдХрд░реЗрдВрдЧреЗред рд╣рдореЗрдВ рдЕрдкрдиреЗ рдШрдЯрдХ рдореЗрдВ рдЗрди рдХрдиреНрд╡рд░реНрдЯрд░реНрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред

рд╕рдмрд╕реЗ рд╕рд░рд▓ рдкреЛрд╕реНрдЯ-рдХрдиреНрд╡рд░реНрдЯрд░ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

  Converter<UnicornDto, Unicorn> toEntityConverter() { return MappingContext::getDestination; } 

рд╣рдореЗрдВ рдЗрд╕рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХрд╛ рд╡рд┐рд╕реНрддрд╛рд░ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ:

  public Converter<UnicornDto, Unicorn> toEntityConverter() { return context -> { UnicornDto source = context.getSource(); Unicorn destination = context.getDestination(); mapSpecificFields(source, destination); return context.getDestination(); }; } 

рд╣рдо рдЙрд▓рдЯрд╛ рдХрдирд╡рд░реНрдЯрд░ рдХреЗ рд╕рд╛рде рднреА рдРрд╕рд╛ рд╣реА рдХрд░рддреЗ рд╣реИрдВ:

  public Converter<Unicorn, UnicornDto> toDtoConverter() { return context -> { Unicorn source = context.getSource(); UnicornDto destination = context.getDestination(); mapSpecificFields(source, destination); return context.getDestination(); }; } 

рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рд╣рдо рдмрд╕ рдкреНрд░рддреНрдпреЗрдХ рдкреЛрд╕реНрдЯ-рдХрдиреНрд╡рд░реНрдЯрд░ рдореЗрдВ рдПрдХ рдЕрддрд┐рд░рд┐рдХреНрдд рд╡рд┐рдзрд┐ рд╕рдореНрдорд┐рд▓рд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдореЗрдВ рд╣рдо рд▓рд╛рдкрддрд╛ рдлрд╝реАрд▓реНрдб рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рддрд░реНрдХ рд▓рд┐рдЦрддреЗ рд╣реИрдВред

  public void mapSpecificFields(Droid source, DroidDto destination) { destination.setUnicornId(Objects.isNull(source) || Objects.isNull(source.getId()) ? null : source.getUnicorn().getId()); } void mapSpecificFields(DroidDto source, Droid destination) { destination.setUnicorn(unicornRepository.findById(source.getUnicornId()).orElse(null)); } 

рдбреАрдЯреАрдУ рдореЗрдВ рдореИрдкрд┐рдВрдЧ рдХрд░рддреЗ рд╕рдордп, рд╣рдо рдПрдВрдЯрд┐рдЯреА рдЖрдИрдбреА рд╕реЗрдЯ рдХрд░рддреЗ рд╣реИрдВред рдбреАрдЯреАрдУ рдореЗрдВ рдореИрдкрд┐рдВрдЧ рдХрд░рддреЗ рд╕рдордп, рд╣рдореЗрдВ рдЖрдИрдбреА рджреНрд╡рд╛рд░рд╛ рд░рд┐рдкреЙрдЬрд┐рдЯрд░реА рд╕реЗ рдЗрдХрд╛рдИ рдкреНрд░рд╛рдкреНрдд рд╣реЛрддреА рд╣реИред

рдФрд░ рд╡рд╣ рдпрд╣ рд╣реИред

рдореИрдВрдиреЗ рдореЙрдбрд▓рдореИрдкрд░ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░рдирд╛ рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдиреНрдпреВрдирддрдо рджрд┐рдЦрд╛рдпрд╛ рдФрд░ рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ рдХреЛрдб рдХреЛ рд░рд┐рдлрд▓реЗрдХреНрдЯрд░ рдирд╣реАрдВ рдХрд┐рдпрд╛ред рдпрджрд┐ рдЖрдк, рдкрд╛рдардХ, рдореЗрд░реЗ рд▓реЗрдЦ рдореЗрдВ рдХреБрдЫ рдЬреЛрдбрд╝рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ, рддреЛ рдореБрдЭреЗ рд░рдЪрдирд╛рддреНрдордХ рдЖрд▓реЛрдЪрдирд╛ рд╕реБрдирдХрд░ рдЦреБрд╢реА рд╣реЛрдЧреАред

рдЗрд╕ рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХреЛ рдпрд╣рд╛рдВ рджреЗрдЦрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ:
GitHub рдкрд░ рдкрд░рд┐рдпреЛрдЬрдирд╛ред

рд╕реНрд╡рдЪреНрдЫ рдХреЛрдб рдХреЗ рдкреНрд░рд╢рдВрд╕рдХреЛрдВ рдиреЗ рд╕рдВрднрд╡рддрдГ рдкрд╣рд▓реЗ рд╕реЗ рд╣реА рдХрдИ рдХреЛрдб рдШрдЯрдХреЛрдВ рдХреЛ рдПрдХ рдЕрдореВрд░реНрдд рдореЗрдВ рдбреНрд░рд╛рдЗрд╡ рдХрд░рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рджреЗрдЦрд╛ рдерд╛ред рдпрджрд┐ рдЖрдк рдЙрдирдореЗрдВ рд╕реЗ рдПрдХ рд╣реИрдВ, рддреЛ рдореИрдВ рдмрд┐рд▓реНрд▓реА рдХреЗ рдиреАрдЪреЗ рд╕реБрдЭрд╛рд╡ рджреЗрддрд╛ рд╣реВрдВред

рдЕрдореВрд░реНрдд рдХреЗ рд╕реНрддрд░ рдХреЛ рдЙрдард╛рдПрдВ
рд╢реБрд░реВ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдо рд░реИрдкрд░ рдХреНрд▓рд╛рд╕ рдХреЗ рдмреБрдирд┐рдпрд╛рджреА рддрд░реАрдХреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдкрд░рд┐рднрд╛рд╖рд┐рдд рдХрд░рддреЗ рд╣реИрдВред

 public interface Mapper<E extends AbstractEntity, D extends AbstractDto> { E toEntity(D dto); D toDto(E entity); } 

рд╣рдо рдЗрд╕реЗ рдПрдХ рдЕрдореВрд░реНрдд рд╡рд░реНрдЧ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВред

 public abstract class AbstractMapper<E extends AbstractEntity, D extends AbstractDto> implements Mapper<E, D> { @Autowired ModelMapper mapper; private Class<E> entityClass; private Class<D> dtoClass; AbstractMapper(Class<E> entityClass, Class<D> dtoClass) { this.entityClass = entityClass; this.dtoClass = dtoClass; } @Override public E toEntity(D dto) { return Objects.isNull(dto) ? null : mapper.map(dto, entityClass); } @Override public D toDto(E entity) { return Objects.isNull(entity) ? null : mapper.map(entity, dtoClass); } Converter<E, D> toDtoConverter() { return context -> { E source = context.getSource(); D destination = context.getDestination(); mapSpecificFields(source, destination); return context.getDestination(); }; } Converter<D, E> toEntityConverter() { return context -> { D source = context.getSource(); E destination = context.getDestination(); mapSpecificFields(source, destination); return context.getDestination(); }; } void mapSpecificFields(E source, D destination) { } void mapSpecificFields(D source, E destination) { } } 

рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рднрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдкреЛрд╕реНрдЯ-рдХрдиреНрд╡рд░реНрдЯрд░реНрд╕ рдФрд░ рддрд░реАрдХреЗ рд╕реБрд░рдХреНрд╖рд┐рдд рд░реВрдк рд╕реЗ рд╡рд╣рд╛рдВ рднреЗрдЬреЗ рдЬрд╛ рд╕рдХрддреЗ рд╣реИрдВред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдЙрдиреНрд╣реЗрдВ рдЯрд╛рдЗрдк рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЯрд╛рдЗрдк рдХреНрд▓рд╛рд╕ рдФрд░ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдХреЗ рджреЛ рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдПрдВ:

  private Class<E> entityClass; private Class<D> dtoClass; AbstractMapper(Class<E> entityClass, Class<D> dtoClass) { this.entityClass = entityClass; this.dtoClass = dtoClass; } 

рдЕрдм DroidMapper рдореЗрдВ рдХреЛрдб рдХреА рдорд╛рддреНрд░рд╛ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдХреЗ рд▓рд┐рдП рдХрдо рд╣реЛ рдЧрдИ рд╣реИ:

 @Component public class DroidMapper extends AbstractMapper<Droid, DroidDto> { private final ModelMapper mapper; private final UnicornRepository unicornRepository; @Autowired public DroidMapper(ModelMapper mapper, UnicornRepository unicornRepository) { super(Droid.class, DroidDto.class); this.mapper = mapper; this.unicornRepository = unicornRepository; } @PostConstruct public void setupMapper() { mapper.createTypeMap(Droid.class, DroidDto.class) .addMappings(m -> m.skip(DroidDto::setUnicornId)).setPostConverter(toDtoConverter()); mapper.createTypeMap(DroidDto.class, Droid.class) .addMappings(m -> m.skip(Droid::setUnicorn)).setPostConverter(toEntityConverter()); } @Override public void mapSpecificFields(Droid source, DroidDto destination) { destination.setUnicornId(getId(source)); } private Long getId(Droid source) { return Objects.isNull(source) || Objects.isNull(source.getId()) ? null : source.getUnicorn().getId(); } @Override void mapSpecificFields(DroidDto source, Droid destination) { destination.setUnicorn(unicornRepository.findById(source.getUnicornId()).orElse(null)); } } 

рд╡рд┐рд╢рд┐рд╖реНрдЯ рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рдмрд┐рдирд╛ рдПрдХ рдореИрдкрд░ рдЖрдорддреМрд░ рдкрд░ рд╕рд░рд▓ рджрд┐рдЦрддрд╛ рд╣реИ:

 @Component public class UnicornMapper extends AbstractMapper<Unicorn, UnicornDto> { @Autowired public UnicornMapper() { super(Unicorn.class, UnicornDto.class); } } 

Source: https://habr.com/ru/post/hi438808/


All Articles