Pull to refresh

Comments 10

UFO just landed and posted this here
Ну, не такие уж они и магические :)

Затрудняют поиск использования полей в коде

Каким образом? Можете привести пример?

При внесении изменении в entity/dto проблемы сломанного мапинга будут видны только в рантайме

Для защиты от таких ситуаций программисты пишут тесты.
с ModelMapper не работал, использую MapStruct, и там это решается следующим образом
— Затрудняют поиск использования полей в коде

маппинг делается в интерфейсах, для которых генерируются реализации. в реализациях маппинг прописан явно, проблема с поиском отпадает
— При внесении изменении в entity/dto проблемы сломанного мапинга будут видны только в рантайме

если что-то пойдёт не так, приложение просто не соберётся
Поэтому, правильным решением является использование библиотеки-маппера.

Не могу согласиться. В данном примере код, завязанный на библиотеку тоже имеет ряд недостатков:
  • Возможность конфликтов с другими библиотеками (несовместимость аннотаций)
  • Нет гарантии, что после обновлении версии библиотеки не придется переписывать маппинг всех Entities, DTOs (breaking changes)
  • Изменилось поле, напиши конвертер
  • Опять не уйти от абстракции, чтобы скрыть реализацию. В сути получаем тот же «колхозный» ItemMapper на базе библиотеки.

Как решить проблему, если DTO имеет другую (схожую) структуру с Entity. Например в DTO вычислимое поле А, которое состоит из суммы полей B и C соответствующей Entity. Писать для каждого случая постконвертер (TypeMap)?

Конечно, если Entities толстые, может и имеет смысл использовать библиотеку. Но скорее всего проблема вытекает из другого места.
Возможность конфликтов с другими библиотеками (несовместимость аннотаций)

С тем же Lombok ModelMapper не конфликтует. Если Вы пишете свою какую-то аннотацию, то да, будьте готовы, что библиотеки не будут её понимать.

Нет гарантии, что после обновлении версии библиотеки не придется переписывать маппинг всех Entities, DTOs (breaking changes)

А есть примеры таких конфликтов и переписывания сущностей на примере ModelMapper?

Изменилось поле, напиши конвертер

Сущность является фундаментом любого приложения, если Вы меняете поля в сущности, Вам придётся всё приложение перелопатить. А вот ModelMapper, кстати, по умолчанию работает с полями и пытается их корректно замапить. Конвертер нужно писать только для специфичного мапинга. Так что, вполне вероятно, как раз он и сэкономит Ваше время :) Но проверять, конечно, надо. Тесты в помощь.

Опять не уйти от абстракции, чтобы скрыть реализацию. В сути получаем тот же «колхозный» ItemMapper на базе библиотеки.

Не понял, что Вы хотели сказать.

Как решить проблему, если DTO имеет другую (схожую) структуру с Entity. Например в DTO вычислимое поле А, которое состоит из суммы полей B и C соответствующей Entity. Писать для каждого случая постконвертер (TypeMap)?

В этом и смысл использования библиотек. Все специфичные поля библиотека обрабатывает сама. Обработку неспецифичных полей никто кроме Вас не напишет.
Не понял, что Вы хотели сказать.

В месте использования предпочтительнее работать с некоторой абстракцией над маппингом.

В этом и смысл использования библиотек. Все специфичные поля библиотека обрабатывает сама. Обработку неспецифичных полей никто кроме Вас не напишет.

Выходит тащим библиотеку для решение проблемы, в итоге получаем частичное решение проблемы + зависимости.
Ни одна библиотека не решает проблему целиком, тут Вы правы.
А в modelMapper можно посмотреть получившиеся мапперы? Он их генерирует или как? Рефлексирует в runtime как Dozer? Если что-то не маппится, то он в runtime упадёт или при компиляции? Хотелось бы увидеть описание того, как он работает под капотом, подробностей реализации. Чем он лучше других решений?

MapStruct прекрасен тем, что по интерфейсам с аннотациями(это поле в вот это поле, если есть разногласия) или абстрактным классам (если надо сделать что-то больше, чем просто «из этого поля в это») просто сгенерит реализующий класс, где будет тупо использование геттеров-сеттеров и создание объектов. Как будто вы писали это влоб руками. Сгенерированный конвертер можно тестить, можно дебажить. Он просто используется в runtime. Никаких оверхедов на рефлексию. Если что-то не маппится, то падает при компиляции.
Хорошо бы увидеть обстоятельную статью по Mapstruct на хабре, но её нет…
Если есть шанс отрефакторить фронт или энтити, чтоб они понимали друг-друга без компараторов лучше это сделать, а не городить компараторы.

Если есть возможность обойтись аннотациями стандартного Спринговского сериализатора, нужно ими обойтись.

Если структура Энтити и требуемого ДТО({id:1, fio:{name:dima}}->{id:1.name:dima}) кардинально различается, то можно опять же попытаться обойтись стандартным спринговским маппером, написав нативный SQL/HQL запрос, который автоматом попытается наложиться на требуемую ДТО. Это будет быстродейственней и короче.

Ну и если уж компарить надо сильно много и сильно кастомно, то это пардон уже не компаратор, а бизнес-логика.
Sign up to leave a comment.

Articles