ModelMapper: ุฐู‡ุงุจุง ูˆุฅูŠุงุจุง

ุงู„ุตูˆุฑุฉ

ู„ุฃุณุจุงุจ ู…ุนุฑูˆูุฉ ุŒ ู„ุง ูŠู…ูƒู† ู„ู„ุฌู‡ุฉ ุงู„ุฎู„ููŠุฉ ุฅุฑุฌุงุน ุงู„ุจูŠุงู†ุงุช ู…ู† ุงู„ู…ุณุชูˆุฏุน ูƒู…ุง ู‡ูŠ. ุงู„ุฃูƒุซุฑ ุดู‡ุฑุฉ - ู„ุง ุชุคุฎุฐ ุงู„ุชุจุนูŠุงุช ุงู„ุฃุณุงุณูŠุฉ ู…ู† ุงู„ู‚ุงุนุฏุฉ ููŠ ุงู„ุดูƒู„ ุงู„ุฐูŠ ูŠู…ูƒู† ู„ู„ุฌุจู‡ุฉ ูู‡ู…ู‡ุง. ู‡ู†ุง ูŠู…ูƒู†ูƒ ุฅุถุงูุฉ ุตุนูˆุจุงุช ููŠ ุชุญู„ูŠู„ ุงู„ุชุนุฏุงุฏ (ุฅุฐุง ูƒุงู†ุช ุญู‚ูˆู„ ุงู„ุชุนุฏุงุฏ ุชุญุชูˆูŠ ุนู„ู‰ ู…ุนู„ู…ุงุช ุฅุถุงููŠุฉ) ุŒ ูˆุงู„ุนุฏูŠุฏ ู…ู† ุงู„ุตุนูˆุจุงุช ุงู„ุฃุฎุฑู‰ ุงู„ู†ุงุดุฆุฉ ุนู† ุงู„ุตุจ ุงู„ุชู„ู‚ุงุฆูŠ ู„ู„ูƒุชุงุจุฉ (ุฃูˆ ุนุฏู… ุงู„ู‚ุฏุฑุฉ ุนู„ู‰ ุฅู„ู‚ุงุกู‡ุง ุชู„ู‚ุงุฆูŠู‹ุง). ู‡ุฐุง ูŠุนู†ูŠ ุงู„ุญุงุฌุฉ ุฅู„ู‰ ุงุณุชุฎุฏุงู… ูƒุงุฆู† ู†ู‚ู„ ุงู„ุจูŠุงู†ุงุช - DTO ุŒ ูˆู‡ูˆ ุฃู…ุฑ ู…ูู‡ูˆู… ู„ูƒู„ ู…ู† ุงู„ุฎู„ู ูˆุงู„ุฃู…ุงู….
ูŠู…ูƒู† ุฅุฌุฑุงุก ุชุญูˆูŠู„ ูƒูŠุงู† ุฅู„ู‰ DTO ุจุนุฏุฉ ุทุฑู‚ ู…ุฎุชู„ูุฉ. ูŠู…ูƒู†ูƒ ุงุณุชุฎุฏุงู… ุงู„ู…ูƒุชุจุฉ ุŒ ูŠู…ูƒู†ูƒ (ุฅุฐุง ูƒุงู† ุงู„ู…ุดุฑูˆุน ุตุบูŠุฑู‹ุง) ุฅู†ุดุงุก ุดูŠุก ู…ุซู„ ู‡ุฐุง:

@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. ุนู†ุฏ ุฅุถุงูุฉ / ุฅุฒุงู„ุฉ ุญุชู‰ ุงู„ุญู‚ู„ ุงู„ุฃูƒุซุฑ ุฃู‡ู…ูŠุฉ ุŒ ุณูŠูƒูˆู† ุนู„ูŠูƒ ุชุญุฑูŠุฑ ุงู„ู…ุฎุทุท.

ู„ุฐู„ูƒ ุŒ ุงู„ุญู„ ุงู„ุตุญูŠุญ ู‡ูˆ ุงุณุชุฎุฏุงู… ู…ูƒุชุจุฉ ู…ุนูŠู†. ุฃู†ุง ุฃุนุฑู modelmapper ูˆ mapstruct. ู…ู†ุฐ ุฃู† ุนู…ู„ุช ู…ุน ุนุงุฑุถ ุงู„ู†ู…ุงุฐุฌ ุŒ ุณุฃุชุญุฏุซ ุนู† ุฐู„ูƒ ุŒ ู„ูƒู† ุฅุฐุง ูƒู†ุช ุŒ ุฃูŠู‡ุง ุงู„ู‚ุงุฑุฆ ุงู„ุฎุงุต ุจูƒ ุŒ ุนู„ู‰ ุฏุฑุงูŠุฉ ุฌูŠุฏุฉ ุจู€ mapstruct ูˆูŠู…ูƒู† ุฃู† ุชุฎุจุฑู†ุง ุจูƒู„ ุงู„ุชูุงุตูŠู„ ุงู„ุฏู‚ูŠู‚ุฉ ู„ุชุทุจูŠู‚ู‡ ุŒ ููŠุฑุฌู‰ ูƒุชุงุจุฉ ู…ู‚ุงู„ ุญูˆู„ู‡ ุŒ ูˆุณุฃูƒูˆู† ุฃูˆู„ ู…ู† ูŠูƒุชุจู‡ ู„ูŠ (ู‡ุฐู‡ ุงู„ู…ูƒุชุจุฉ ู‡ูŠ ุฃูŠุถู‹ุง ู…ุซูŠุฑุฉ ู„ู„ุงู‡ุชู…ุงู… ุŒ ูˆู„ูƒู† ู„ูŠุณ ู‡ู†ุงูƒ ูˆู‚ุช ู„ู„ุฏุฎูˆู„ ุฅู„ูŠู‡ุง ุญุชู‰ ุงู„ุขู†).

ู„ุฐู„ูƒ modelmapper.

ุฃุฑูŠุฏ ุฃู† ุฃู‚ูˆู„ ุนู„ู‰ ุงู„ููˆุฑ ุฃู†ู‡ ุฅุฐุง ูƒุงู† ู‡ู†ุงูƒ ุดูŠุก ุบูŠุฑ ูˆุงุถุญ ู„ูƒ ุŒ ููŠู…ูƒู†ูƒ ุชู†ุฒูŠู„ ุงู„ู…ุดุฑูˆุน ุงู„ู†ู‡ุงุฆูŠ ู…ู† ุฎู„ุงู„ ุงุฎุชุจุงุฑ ุนู…ู„ูŠ ุŒ ุฑุงุจุท ููŠ ู†ู‡ุงูŠุฉ ุงู„ู…ู‚ุงู„ุฉ.

ุงู„ุฎุทูˆุฉ ุงู„ุฃูˆู„ู‰ ู‡ูŠ ุŒ ุจุงู„ุทุจุน ุŒ ุฅุถุงูุฉ ุชุจุนูŠุฉ. ุฃุณุชุฎุฏู… ู…ูŠุฒุฉ gradle ุŒ ู„ูƒู† ู…ู† ุงู„ุณู‡ู„ ุนู„ูŠูƒ ุฅุถุงูุฉ ุชุจุนูŠุฉ ุฅู„ู‰ ู…ุดุฑูˆุน maven ุงู„ุฎุงุต ุจูƒ.

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

ุงู„ุฑูˆุจูˆุช:

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


ุณู†ู‚ูˆู… ุจุชุญูˆูŠู„ ู‡ุฐู‡ ุงู„ูƒูŠุงู†ุงุช ุฅู„ู‰ DTO. ู‡ู†ุงูƒ ุทุฑูŠู‚ุชุงู† ุนู„ู‰ ุงู„ุฃู‚ู„ ู„ุชุญูˆูŠู„ ุงู„ุชุจุนูŠุงุช ู…ู† ูƒูŠุงู† ุฅู„ู‰ DTO. ูˆุงุญุฏ ูŠุนู†ูŠ ุญูุธ ุงู„ู…ุนุฑู ูู‚ุท ุจุฏู„ุงู‹ ู…ู† ุงู„ูƒูŠุงู† ุŒ ูˆู„ูƒู† ุจุนุฏ ุฐู„ูƒ ูƒู„ ูƒูŠุงู† ู…ู† ุงู„ุชุจุนูŠุฉ ุŒ ุฅุฐุง ู„ุฒู… ุงู„ุฃู…ุฑ ุŒ ุณู†ู‚ูˆู… ุจุณุญุจ ุงู„ู…ุนุฑู ุจุงู„ุฅุถุงูุฉ ุฅู„ู‰ ุฐู„ูƒ. ุงู„ู†ู‡ุฌ ุงู„ุซุงู†ูŠ ูŠู†ุทูˆูŠ ุนู„ู‰ ุงู„ุญูุงุธ ุนู„ู‰ DTO ุงู„ุชุงุจุนุฉ. ู„ุฐู„ูƒ ุŒ ููŠ ุงู„ุทุฑูŠู‚ุฉ ุงู„ุฃูˆู„ู‰ ุŒ ุณู†ู‚ูˆู… ุจุชุญูˆูŠู„ List droids ุฅู„ู‰ List droids (ู†ู‚ูˆู… ูู‚ุท ุจุชุฎุฒูŠู† ุงู„ู…ุนุฑูุงุช ููŠ ุงู„ู‚ุงุฆู…ุฉ ุงู„ุฌุฏูŠุฏุฉ) ุŒ ูˆููŠ ุงู„ุทุฑูŠู‚ุฉ ุงู„ุซุงู†ูŠุฉ ุŒ ุณูˆู ู†ู‚ูˆู… ุจุญูุธู‡ุง ููŠ List droids.

DTO
ุงู„ุฃุตู„ ู…ุฌุฑุฏุฉ:

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

ุงู„ุขู† ุŒ ูŠูƒููŠ ุฃู† ู†ุถูŠู ู…ุตู…ู… ุงู„ุฎุฑุงุฆุท ุงู„ุฎุงุต ุจู†ุง ุฅู„ู‰ ุฎุฏู…ุฉ ู…ุง ูˆุณุญุจู‡ุง ุจุงุณุชุฎุฏุงู… ุฃุณุงู„ูŠุจ toDto ูˆ toEntity. ุณูŠู‚ูˆู… ู…ุฎุทุท ู…ุนูŠู† ุจุชุญูˆูŠู„ ุงู„ูƒูŠุงู†ุงุช ุงู„ู…ูˆุฌูˆุฏุฉ ููŠ ุงู„ูƒุงุฆู† ุฅู„ู‰ 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)); } } 

ูˆู„ูƒู† ุฅุฐุง ุญุงูˆู„ู†ุง ุชุญูˆูŠู„ ุดูŠุก ู…ุง ุจู‡ุฐู‡ ุงู„ุทุฑูŠู‚ุฉ ุŒ ุซู… ุงุชุตู„ู†ุง ุŒ ุนู„ู‰ ุณุจูŠู„ ุงู„ู…ุซุงู„ ุŒ ุจู€ "ุณู„ุณู„ุฉ" ุŒ ูุณู†ุญุตู„ ุนู„ู‰ StackOverflowException ุŒ ูˆุฅู„ูŠูƒู… ุงู„ุณุจุจ: ูŠุญุชูˆูŠ UnicornDto ุนู„ู‰ ู‚ุงุฆู…ุฉ DroidDto ุŒ ุงู„ุชูŠ ุชุญุชูˆูŠ ุนู„ู‰ UnicornDto ุŒ ูˆุงู„ุชูŠ ุชุญุชูˆูŠ ุนู„ู‰ DroidDto ุŒ ูˆู‡ูƒุฐุง ุญุชู‰ ุชู„ูƒ ุงู„ู„ุญุธุฉ ุญุชู‰ ู†ูุงุฏ ุฐุงูƒุฑุฉ ุงู„ู…ูƒุฏุณ. ู„ุฐู„ูƒ ุŒ ุจุงู„ู†ุณุจุฉ ุฅู„ู‰ ุงู„ุชุจุนูŠุงุช ุงู„ู…ุนูƒูˆุณุฉ ุŒ ุนุงุฏุฉู‹ ู…ุง ุฃุณุชุฎุฏู… UnicornDto unicorn ุŒ ู„ูƒู† Long unicornId. ูˆุจู‡ุฐู‡ ุงู„ุทุฑูŠู‚ุฉ ุŒ ู†ุจู‚ู‰ ุนู„ู‰ ุงุชุตุงู„ ู…ุน ูŠูˆู†ูŠูƒูˆุฑู† ุŒ ู„ูƒู†ู†ุง ู†ู‚ุทุน ุงู„ุงุนุชู…ุงุฏ ุงู„ุชุจุนูŠ ุงู„ุฏูˆุฑูŠ. ุฏุนูˆู†ุง ุฅุตู„ุงุญ DTOs ู„ุฏูŠู†ุง ุจุญูŠุซ ุจุฏู„ุงู‹ ู…ู† DTOs ุงู„ุนูƒุณูŠ ุŒ ูุฅู†ู‡ุง ุชุฎุฒู† ู…ุนุฑูุงุช ุชุจุนูŠุงุชู‡ู….

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

ูˆ ู‡ูƒุฐุง.

ูˆู„ูƒู† ุงู„ุขู† ุŒ ุฅุฐุง ุงุชุตู„ู†ุง ุจู€ DroidMapper ุŒ ูุณู†ุญุตู„ ุนู„ู‰ unicornId == ูุงุฑุบุฉ. ู‡ุฐุง ู„ุฃู†ู‡ ู„ุง ูŠู…ูƒู† ู„ู€ ModelMapper ุชุญุฏูŠุฏ ู†ูˆุน Long ุจุงู„ุถุจุท. ูˆูู‚ุท ู„ุง ูŠุฒุนุฌู‡. ูˆุณูŠุชุนูŠู† ุนู„ูŠู†ุง ุถุจุท ุงู„ู…ุตู…ู…ูŠู† ุงู„ุถุฑูˆุฑูŠูŠู† ู„ุชุนู„ูŠู…ู‡ู… ูƒูŠููŠุฉ ุชุนูŠูŠู† ุงู„ูƒูŠุงู†ุงุช ููŠ ุงู„ู…ุนุฑูุงุช.

ู†ุฐูƒุฑ ุฃู†ู‡ ู…ุน ูƒู„ ุตู†ุฏูˆู‚ ุจุนุฏ ุงู„ุชู‡ูŠุฆุฉ ุŒ ูŠู…ูƒู†ูƒ ุงู„ุนู…ู„ ูŠุฏูˆูŠู‹ุง.

  @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 ุณู†ุถุน ุงู„ู‚ูˆุงุนุฏ ุงู„ุชูŠ ู†ุดูŠุฑ ููŠู‡ุง ุฅู„ู‰ ุงู„ุญู‚ูˆู„ ุงู„ุชูŠ ู„ุง ูŠุฌุจ ุนู„ู‰ ุงู„ู…ุฎุทุท ุชุนูŠูŠู†ู‡ุง ุŒ ู„ุฃู†ู†ุง ุณู†ุญุฏุฏ ุงู„ู…ู†ุทู‚ ุงู„ุฎุงุต ุจู†ุง. ููŠ ุญุงู„ุชู†ุง ุŒ ู‡ุฐุง ู‡ูˆ ุชุนุฑูŠู unicornId ููŠ DTO ุŒ ูˆุชุนุฑูŠู Unicorn ููŠ ุฌูˆู‡ุฑู‡ (ู†ุธุฑู‹ุง ู„ุฃู† ุงู„ู…ุตู…ู… ู„ุง ูŠุนุฑู ุฃูŠุถู‹ุง ู…ุง ูŠุฌุจ ูุนู„ู‡ ู…ุน Long unicornId).

TypeMap - ู‡ุฐู‡ ู‡ูŠ ุงู„ู‚ุงุนุฏุฉ ุงู„ุชูŠ ู†ุญุฏุฏ ููŠู‡ุง ุฌู…ูŠุน ุงู„ูุฑูˆู‚ ุงู„ุฏู‚ูŠู‚ุฉ ููŠ ุงู„ุชุนูŠูŠู† ุŒ ูˆุฃูŠุถู‹ุง ุŒ ู‚ู… ุจุชุนูŠูŠู† ุงู„ู…ุญูˆู„. ู„ู‚ุฏ ุฃูˆุถุญู†ุง ุฃู†ู‡ ู„ู„ุชุญูˆูŠู„ ู…ู† Droid ุฅู„ู‰ DroidDto ุŒ ู†ุชุฎุทู‰ setUnicornId ุŒ ูˆููŠ ุงู„ุชุญูˆูŠู„ ุงู„ุนูƒุณูŠ ุŒ ู†ู…ุฑ setUnicorn. ุณู†ู‚ูˆู… ุฌู…ูŠุนู‹ุง ุจุงู„ุชุญูˆูŠู„ ููŠ ู…ุญูˆู„ toDtoConverter () ู„ู€ UnicornDto ูˆููŠ toEntityConverter () ู„ู€ Unicorn. ูŠุฌุจ ุฃู† ู†ุตู ู‡ุฐู‡ ุงู„ู…ุญูˆู„ุงุช ููŠ ุงู„ู…ูƒูˆู† ุงู„ุฎุงุต ุจู†ุง.

ุฃุจุณุท ู…ุง ุจุนุฏ ุงู„ู…ุญูˆู„ ูŠุดุจู‡ ู‡ุฐุง:

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

ุนู†ุฏ ุงู„ุชุนูŠูŠู† ููŠ DTO ุŒ ู†ู‚ูˆู… ุจุชุนูŠูŠู† ู…ุนุฑู ุงู„ูƒูŠุงู†. ุนู†ุฏ ุงู„ุชุนูŠูŠู† ููŠ DTO ุŒ ู†ุญุตู„ ุนู„ู‰ ุงู„ูƒูŠุงู† ู…ู† ุงู„ู…ุณุชูˆุฏุน ุจู…ุนุฑู.

ูˆู‡ุฐุง ูƒู„ ุดูŠุก.

ู„ู‚ุฏ ุฃุธู‡ุฑุช ุงู„ุญุฏ ุงู„ุฃุฏู†ู‰ ุงู„ุถุฑูˆุฑูŠ ู„ุจุฏุก ุงู„ุนู…ู„ ู…ุน modelmapper ูˆู„ู… ุชู‚ู… ุจุฅุนุงุฏุฉ ุชุดูƒูŠู„ ุงู„ุฑู…ุฒ ุจุดูƒู„ ุฎุงุต. ุฅุฐุง ูƒู†ุช ุŒ ุฃูŠู‡ุง ุงู„ู‚ุงุฑุฆ ุŒ ู„ุฏูŠูƒ ู…ุง ุชุถูŠูู‡ ุฅู„ู‰ ู…ู‚ุงู„ุชูŠ ุŒ ูุณุฃูƒูˆู† ุณุนูŠุฏู‹ุง ู„ุณู…ุงุน ุงู„ู†ู‚ุฏ ุงู„ุจู†ุงุก.

ูŠู…ูƒู† ุงู„ุงุทู„ุงุน ุนู„ู‰ ุงู„ู…ุดุฑูˆุน ู‡ู†ุง:
ู…ุดุฑูˆุน ุนู„ู‰ ุฌูŠุซุจ.

ู…ู† ุงู„ู…ุญุชู…ู„ ุฃู† ูŠูƒูˆู† ุนุดุงู‚ ุงู„ูƒูˆุฏ ุงู„ู†ุธูŠู ู‚ุฏ ุฑุฃูˆุง ุจุงู„ูุนู„ ุงู„ูุฑุตุฉ ู„ุฏูุน ุงู„ุนุฏูŠุฏ ู…ู† ู…ูƒูˆู†ุงุช ุงู„ูƒูˆุฏ ุฅู„ู‰ ุงู„ุชุฌุฑูŠุฏ. ุฅุฐุง ูƒู†ุช ูˆุงุญุฏุง ู…ู†ู‡ู… ุŒ ุฃู‚ุชุฑุญ ุชุญุช ุงู„ู‚ุท.

ุฑูุน ู…ุณุชูˆู‰ ุงู„ุชุฌุฑูŠุฏ
ุจุงุฏุฆ ุฐูŠ ุจุฏุก ุŒ ู†ู‚ูˆู… ุจุชุนุฑูŠู ูˆุงุฌู‡ุฉ ู„ู„ุทุฑู‚ ุงู„ุฃุณุงุณูŠุฉ ู„ูุฆุฉ ุงู„ุงู„ุชูุงู.

 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) { } } 

ูŠู…ูƒู† ุฅุฑุณุงู„ ุงู„ู…ุญูˆู„ุงุช ุงู„ู„ุงุญู‚ุฉ ูˆุทุฑู‚ ู…ู„ุก ุงู„ุญู‚ูˆู„ ุงู„ู…ุญุฏุฏุฉ ุจุฃู…ุงู† ุฅู„ู‰ ู‡ู†ุงูƒ. ุฃูŠุถู‹ุง ุŒ ู‚ู… ุจุฅู†ุดุงุก ูƒุงุฆู†ูŠู† ู…ู† ุงู„ู†ูˆุน Class ูˆู…ู†ุดุฆ ู„ุชู‡ูŠุฆุฉู‡ู…ุง:

  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/ar438808/


All Articles