Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

java-object-merger — огромнее чем легко маппер объектов

Anna | 4.06.2014 | нет комментариев
Всем здравствуй! Хотел бы представить вам новую библиотеку на java для маппинга/мержинга объектов, которую я “скромно” позиционирую как допустимую альтернативу dozer-у. Если вы разрабатываете enterprise приложения на java, вам не равнодушна результативность вашей работы, и хочется писать поменьше тоскливого кода, то приглашаю почитать дальше!

Для чего необходимы мапперы объектов?

Примитивный результат: Дабы копировать данные механически из одного объекта в иной. Но тогда вы можете спросить: для чего необходимо это копирование? Дозволено усомниться, что это необходимо дюже Зачастую. Значит следует дать больше развернутый результат.
В мире энтерпрайз приложений принято бить внутреннюю конструкцию на слои: слой доступа к базе, бизнес и представление/веб обслуживания. В слое доступа к базе как правило обитают объекты мапящиеся на таблицы в базе. Условимся называть их DTO (от Data transfer object). По отличному, они только переносят данные из таблиц и не содержат бизнес логики. На слое представления/веб сервисов, находятся объекты, доставляющие данные заказчику (браузер / заказчики веб сервисов). Назовем их VO (от View object). VO могут требовать только часть тех данных, которые есть в DTO, либо же агрегировать данные из нескольких DTO. Они могут добавочно заниматься локализацией либо реформированием данных в комфортный для представления вид. Так что передавать DTO сразу на представление не вовсе верно. Так же изредка в бизнес слое выделяют бизнес объекты BO (Business object). Они являются обертками над DTO и содержат бизнес логику работы с ними: сохранение, модифицирование, бизнес операции. На фоне этого появляется задача по переносу данных между объектами из различных слоев. Скажем, замапить часть данных из DTO на VO. Либо из VO на BO и потом сберечь то что получилось.

Если решать задачу в лоб, то получается приблизительно такой “тупой” код:

…
employeeVO.setPositionName(employee.getPositionName());
employeeVO.setPerson(new PersonVO());
PersionVO personVO = employeeVO.getPerson();
PersonDTD person = employee.getPerson();
personVO.setFirstName(person.getFirstName());
personVO.setMiddleName(person.getMiddleName());
personVO.setLastName(person.getLastName());
...

Знакомо? :) Если да, то могу вас обрадовать. Для этой задачи теснее придумали решение.

Мапперы объектов

Придуманы безусловно-же не мною. Реализаций на java много. Вы можете ознакомится, к примеру здесь.
Лаконично, задача маппера — скопировать все свойства одного объекта в иной, а так же проделать все то же рекурсивно для всех чайлдовых объектов, по ходу делая нужные реформирование типов, если это требуется.
Мапперы из списка выше — все различные, больше либо менее простые. Самый сильный вероятно dozer, с ним я работал около 2 лет, и некоторые вещи в нем перестали устраивать. А безжизненный темп последующей разработки дозера побудили написать свой “велосипед” (да, я знакомился с другими мапперами — для наших требовний они еще дрянней).

Чем дрянен dozer
    1. Бедная помощь конфигурирования через аннотации (есть только @Mapping).
    2. Немыслимо мапить из нескольких полей в одно (к примеру собрать полное имя из имени, фамилии и отчества).
    3. Задачи с маппингом генерик свойств. Если в родительском абстрактном классе есть геттер возвращающий генерик тип T, где <T extends IEntity>, а в чайлде T определен, то при маппинге чайлда будет учитываться только спецификация типа T. Словно бы он IEntity, а не тот, которым он определен в чайлдовом классе…
    4. Классы свойств хранятся как строки во внутреннем кэше дозера, и Дабы получить класс, применяется особый класс лоадер. Задачи с этим появляются в osgi окружении, когда dozer находится в одном бандле, а необходимый класс бина в ином, не доступным из первого. Загвоздку мы побороли хоть и стандартным методом — подсунув необходимый класс лоадер, но сама реализация: беречь класс в виде строки — выглядит необычно. Допустимо это для того Дабы не создавать perm gen space мемори ликов. Но все равно не дюже ясно.
    5. Если что-то внезапно не мапится, то разобраться в этом дюже трудно. Если вы будете дебажить дозер, то осознаете отчего. Там какое-то… легко сумасшедшее нагромождение ООП пат@Mapping — задает путь к полю для маппинга на ином конце ассоциации (скажем “employee.person.firstName”). Может быть указано на классе целевого объекта либо объекта источника.
    6. @Skip — поле не попадает в снапшот, не сравнивается и не мапится.
    7. @Identifier — помечает поле которое считаеся идентификатором бина. Таким образом при сопоставлении коллекций мы будем знать какой объект с каким должен сравниваться. А именно будут сравниваться объекты с совпадающими идентификаторами. Так же, если в процессе использования диффа возникнет надобность сделать бин, и при этом знаменит идентификатор, то будет попытка сначала обнаружить данный бин при помощи зарегистрированных IBeanFinder-ов. Так, реализацияIBeanFInder может искать бины к примеру в базе данных.
    8. @MapFromMany — то же самое что и @Mapping только указывается на классе целевого объекта и разрешает указать массив свойств на объекте источнике которые будут мапится на поле в целевом объекте.
    9. @Converter — разрешает задать на свойстве класс преемник PropertyConverter. — он исполнит реформирование между свойствами. Конвертер свойств непременен при маппинге нескольких полей на одно, т.к. он как раз и должен будет собрать все значения из источника вместе и сформировать из них одно значение.
    10. @OnPropertyChange, @OnBeanMappingStarted, @OnBeanMappingFinished — разрешают пометить способы прослушивающие соответствующие эвенты в жизненном цикле маппинга, которые происходят в данном бине.
    11. И другие.
Реформирования типов
      В IMergingContext дозволено регистрировать пользовательские преобразователи типов, из одного типа в иной (интерфейс

TypeConverter

      ). Типовой комплект преобразователей включает реформирования:
      • простых типов в обертки, и напротив
      • реформирования дат
      • объектов в строку
      • энумы в энумы, и строки в энумы по имени константы энума
Категории объектов
      Маппер разделяет все объекты на такие категории как:
      1. Объекты значения: простые типы, объекты в пакете java.lang, даты, массивы объектов значений. Список классов считающихся значениями дозволено расширять через IMergingConext.
      2. Коллекции — массивы, все наследующиеся от java.util.Collection.
      3. Мапы — все наследующиеся от java.util.Map.
      4. Бины — все остальные.
Эффективность
      Добросовестно говоря, пока писал библиотеку — о продуктивности особенно не задумывался. Да и первоначально в целях высокой продуктивности не было. Впрочем, решил замерять время маппинга N раз на один тестовый объект.

Начальный код теста

      . Объект достаточно трудный, с полями значениями, дочерними бинами, коллекциями и мапами. Для сопоставления взял dozer последней на нынешний момент версии 5.4.0. Ждал, что дозер не оставит никаких шансов. Но получилось вовсе напротив! dozer замапил 5000 тестовых объектов за 32 секунды, а java-object-merger 50000 объектов за 8 секунд. Разница какая-то дикая — в 40 раз…
Использование
      java-object-merger был опробован на нынешнем плане с моей стержневой работы (osgi, spring, hibernate, сотни мапящихся классов). Дабы заменить им дозер всецело ушло менее 1 дня. По ходу находились некоторые очевидные косяки, но, позже исправления, все основные сценарии трудились типично.
Ленивые снапшоты
      Одна из очевидных задач, обнаруженных во время прикручивания маппера к реальному плану было то, что если делать снапшот на DTO у которой есть ленивые списки других сущностей, а те другие ссылаются на третьи и т.д, то за создание одного снапшота дозволено, ненароком, выкачать пол базы. Следственно было решено сделать все свойства в снапшоте ленивыми по умолчанию. Это обозначает, что они не будут вытаскиваться из объектов до момента сопоставления с соответствующим свойством при взятии диффа. Либо пока очевидно не вызовем на снапшоте способ

loadLazyProperties()

      . А при вытаскивании свойства
 Источник: programmingmaster.ru
Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB