Пример сопоставления компонентов Dozer

Dozer — это мощная библиотека, которая может помочь нам избежать большого количества ненужного кода, когда мы хотим скопировать данные из одного bean в другой bean. Это в основном bean to bean mapper, который рекурсивно копирует данные из одного объекта Java в другой объект Java — атрибут за атрибутом.

Мы осознаем его полную способность, когда мы имеем дело с глубоко вложенными сложными Java-бинами, которые мы легко видим в крупных корпоративных приложениях. Чтобы скопировать данные из одного такого большого бина в другой, подобный бин может иметь сотни строк кода

1. Что такое bean mapper и почему он важен

 

В наши дни все корпоративные проекты по своей природе довольно сложны, и обычно для выполнения определенных бизнес-функций нам необходимо вызывать внешние системы, устаревшие компоненты, что требует преобразования различных типов объектов, структура которых более или менее одинакова, например, объект домена во внешний запрос службы / ответ внешней службы в объекты домена и т. д.

 

В реальном мире эти объекты запроса/ответа могут содержать большое количество полей, поэтому, чтобы скопировать данные из одного объекта в другой, если нам нужно написать код вручную, потребуется много кода, например destination.setXYZ(source.getXYZ()), который по своей природе повторяется и подвержен ошибкам с точки зрения пропущенных полей, ошибок сопоставления и т. д.

 

В этом сценарии Bean mapper выходит на сцену и становится очень удобным для копирования значений из одного bean в другой bean с некоторыми простыми конфигурациями и несколькими строками кода. Сегодня мы узнаем о Dozer bean mapper и сделаем демонстрацию как на spring, так и на non-spring способе.

 

 

 

2. Зависимость Dozer Maven

 

Чтобы использовать dozer, нам нужно добавить следующую зависимость в pom.xml нашего проекта maven.

 

<dependency><groupId>net.sf.dozer</groupId><artifactId>dozer</artifactId><version>5.5.1</version></dependency>

 

3. Пример сопоставления компонентов Dozer

У нас есть два класса, ClassA и ClassB, с тремя полями. Имена полей похожи, но их типы данных могут быть разными. Здесь Dozer сможет обработать их автоматически без каких-либо специальных действий.

package com.example.howtodoinjava.dozer.simple;public class ClassA {private String name;private String age;private String address;//Getters and Setters}
package com.example.howtodoinjava.dozer.simple;public class ClassB {private String name;private int age;private String address;//Getters and Setters}

Простой пример сопоставления компонентов Dozer.

package com.example.howtodoinjava.dozer.simple;import org.dozer.DozerBeanMapper;public class SimpleExample{public static void main(String[] args){ClassA classA = new ClassA();classA.setAddress("India");classA.setName("Sajal");classA.setAge("50");ClassB classB = new DozerBeanMapper().map(classA, ClassB.class);System.out.println(classB);}}

Вывод программы.

Output: ClassB toString after applying Dozer transformation : ClassB [name=Sajal, age=50, address=India]

 

4. Картографирование компонентов Dozer с помощью XML-картографирования

В этом примере SourceObject содержит список объектов Student и несколько других полей. Аналогично, DestinationObject также имеет список объектов StudentVO вместе с несколькими другими простыми полями. Мы будем использовать XML-файл сопоставления для сопоставления атрибутов SourceObject с DestinationObject.

package com.example.howtodoinjava.dozer.models;import java.util.ArrayList;import java.util.List;public class SourceObject {private String name;private String address;List<Student> students;//Getters and Setters}
package com.example.howtodoinjava.dozer.models;public class Student {String name;String batch;String address;//Getters and Setters}
package com.example.howtodoinjava.dozer.models;import java.util.ArrayList;import java.util.List;public class DestinationObject {private String name;private String address;List<StudentVO> pupils;//Getters and Setters}
package com.example.howtodoinjava.dozer.models;public class StudentVO {String name;String batchName;String homeAddress;//Getters and Setters}

XML-файл сопоставления компонентов приведен ниже.

<?xml version="1.0" encoding="UTF-8"?><mappings xmlns="http://dozer.sourceforge.net"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozer.sourceforge.nethttps://dozer.sourceforge.net/schema/beanmapping.xsd%22><mapping><class-a>com.example.howtodoinjava.dozer.models.SourceObject</class-a><class-b>com.example.howtodoinjava.dozer.models.DestinationObject</class-b><field><a>students</a><b>pupils</b></field></mapping><mapping><class-a>com.example.howtodoinjava.dozer.models.Student</class-a><class-b>com.example.howtodoinjava.dozer.models.StudentVO</class-b><field><a>batch</a><b>batchName</b></field><field><a>address</a><b>homeAddress</b></field></mapping></mappings>

Подробную информацию можно найти в руководстве пользователя бульдозера.

package com.example.howtodoinjava.dozer.demo.withoutspring;import java.util.Arrays;import org.dozer.DozerBeanMapper;import com.example.howtodoinjava.dozer.models.DestinationObject;import com.example.howtodoinjava.dozer.models.SourceObject;import com.example.howtodoinjava.dozer.models.Student;public class Demo {public static void main(String[] args){DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();SourceObject sourceObject = new SourceObject();sourceObject.setName("Sajal");sourceObject.setAddress("India");sourceObject.getStudents().add(new Student("S1", "C1", "diffField1"));sourceObject.getStudents().add(new Student("S2", "C2", "diffField2"));sourceObject.getStudents().add(new Student("S3", "C3", "diffField3"));dozerBeanMapper.setMappingFiles(Arrays.asList("mappings\\student-mapper.xml"));DestinationObject destinationObject = dozerBeanMapper.map(sourceObject, DestinationObject.class);System.out.println(destinationObject);}}

Вывод программы.

DestinationObject [name=Sajal, address=India, pupils=[StudentVO [name=S1, batchName=C1, homeAddress=diffField1],StudentVO [name=S2, batchName=C2, homeAddress=diffField2],StudentVO [name=S3, batchName=C3, homeAddress=diffField3]]]

 

5. Аннотации картографирования компонентов Dozer – @Mapping

Конфигурация Dozer также может быть выполнена с помощью аннотации @Mapping, предоставляемой Dozer. Ее можно поместить на само отображаемое свойство, тем самым сократив объем кода.

В настоящее время @Mapping — единственная аннотация, предоставляемая dozer, и она помогает в очень простых отображениях свойств. Если у вас что-то сложное, то используйте XML-отображение или пользовательские конвертеры.

В этом примере я изменил классы, используемые в демонстрации XML-сопоставления, чтобы сохранить сопоставимость подходов.

package com.example.howtodoinjava.dozer.models;import java.util.ArrayList;import java.util.List;public class SourceObject {private String name;private String address;@Mapping("pupils")List<Student> students;//Getters and Setters}
package com.example.howtodoinjava.dozer.models;public class Student {String name;@Mapping("batchName")String batch;@Mapping("homeAddress")String address;//Getters and Setters}
package com.example.howtodoinjava.dozer.models;import java.util.ArrayList;import java.util.List;public class DestinationObject {private String name;private String address;List<StudentVO> pupils;//Getters and Setters}
package com.example.howtodoinjava.dozer.models;public class StudentVO {String name;String batchName;String homeAddress;//Getters and Setters}

Пример аннотации Dozer @Mapping.

import org.dozer.DozerBeanMapper;public class AnnotationExample {public static void main(String[] args){SourceObject sourceObject = new SourceObject();sourceObject.setName("Sajal");sourceObject.setAddress("India");sourceObject.getStudents().add(new Student("S1", "C1", "diffField1"));sourceObject.getStudents().add(new Student("S2", "C2", "diffField2"));sourceObject.getStudents().add(new Student("S3", "C3", "diffField3"));DestinationObject targetObj = new DozerBeanMapper().map(sourceObject, DestinationObject.class);System.out.println("DestinationObject : " + targetObj);}}

Вывод программы.

DestinationObject [name=Sajal, address=India, pupils=[StudentVO [name=S1, batchName=C1, homeAddress=diffField1],StudentVO [name=S2, batchName=C2, homeAddress=diffField2],StudentVO [name=S3, batchName=C3, homeAddress=diffField3]]]

 

6. Пример индивидуальных преобразователей Dozer

До сих пор мы видели, как Dozer может помочь нам в копировании значений полей из исходного в целевой объект. Однако в реальной жизни нам может потребоваться добавить некоторую логику до и после преобразования значений. В этих случаях в игру вступают предоставленные Dozer пользовательские преобразователи. Мы можем добавить любую логику преобразования в эти преобразователи.

В этом примере при копировании из источника в место назначения мы хотим преобразовать строковое значение в ВЕРХНИЙ РЕГИСТР. Давайте посмотрим, как этого можно добиться.

package com.example.howtodoinjava.dozer.converters;public class SourceObject {private String fullname;//Getters, Setters, Constrctors and toString Method}
package com.example.howtodoinjava.dozer.converters;public class DestinationObject {private String fullname;//Getters, Setters, Constrctors and toString Method}

Любой пользовательский конвертер должен будет расширить DozerConverter с параметрами source и destination. Затем нам нужно переопределить методы convertFrom(source, destination) и convertTo(source, destination), чтобы добавить логику для прямых и обратных преобразований.

import org.apache.commons.lang3.StringUtils;import org.dozer.DozerConverter;public class UpperCaseConverter extends DozerConverter<String, String>{public UpperCaseConverter() {super(String.class, String.class);}@Overridepublic String convertFrom(String source, String destination) {if(source != null) {return StringUtils.upperCase(source);}return null;}@Overridepublic String convertTo(String source, String destination) {//No Modification when copy backwardreturn convertTo(source, destination);}}

Теперь нам нужно зарегистрировать этот конвертер в Dozer, мы сделаем это в файле сопоставлений, как показано ниже. Здесь есть несколько вариантов, например, мы можем зарегистрировать пользовательский конвертер в разделе глобальных деклараций или в разделе полей и т. д.

Подробную информацию можно найти в официальной документации по бульдозеру.

<?xml version="1.0" encoding="UTF-8"?><mappings xmlns="http://dozer.sourceforge.net"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://dozer.sourceforge.nethttps://dozer.sourceforge.net/schema/beanmapping.xsd%22><mapping><class-a>com.example.howtodoinjava.dozer.converters.SourceObject</class-a><class-b>com.example.howtodoinjava.dozer.converters.DestinationObject</class-b><field custom-converter="com.example.howtodoinjava.dozer.converters.UpperCaseConverter" custom-converter-param="fullname"><a>fullname</a><b>fullname</b></field></mapping></mappings>

Теперь зарегистрируйте Dozer Bean Mapper весной, как мы уже видели в предыдущем разделе.

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="dozerBeanMapper" class="org.dozer.DozerBeanMapper"><property name="mappingFiles"><list><value>custom-converter-mapping.xml</value></list></property></bean></beans>

Пример программы-конвертера Dozer.

import org.dozer.DozerBeanMapper;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class CustomConverterTest {@SuppressWarnings("resource")public static void main(String[] args) {SourceObject sourceClassForConverters = new SourceObject("Lokesh Gupta");ApplicationContext applicationContext = new ClassPathXmlApplicationContext("custom-converter-spring-beans.xml");DozerBeanMapper beanMapper =(DozerBeanMapper) applicationContext.getBean("dozerBeanMapper");DestinationObject destinationClassForConverters = beanMapper.map(sourceClassForConverters, DestinationObject.class);System.out.println(destinationClassForConverters);}}

Вывод программы.

DestinationObject [fullname=LOKESH GUPTA]

 

7. Пример Dozer BeanMappingBuilder

До сих пор мы учились настраивать Dozer с помощью xml и конфигураций аннотаций. Теперь мы узнаем, как можно программно объявить отображение Dozer с помощью класса BeanMappingBuilder.

В этом примере мы создали два класса SourceObject и DestinationObject. Оба имеют одно поле date, отличается только тип данных.

public class DestinationObject {String date;}
import java.util.Date;public class DestinationObject {Date date;}

Программа Java для демонстрации примера Dozer BeanMappingBuilder.

package com.example.howtodoinjava.dozer.api;import org.dozer.DozerBeanMapper;import org.dozer.loader.api.BeanMappingBuilder;import org.dozer.loader.api.TypeMappingOptions;public class BeanMappingBuilderExample {public static void main(String[] args) {//Bean mappingBeanMappingBuilder beanMappingBuilder = new BeanMappingBuilder() {@Overrideprotected void configure() {String dateFormat = "MM/dd/yyyy HH:mm";mapping(SourceObject.class,DestinationObject.class,TypeMappingOptions.wildcard(true),TypeMappingOptions.dateFormat(dateFormat)).fields("date", "date");}};//ExampleDozerBeanMapper dozerBeanMapper = new DozerBeanMapper();dozerBeanMapper.addMapping(beanMappingBuilder);SourceObject src = new SourceObject();src.setDate("08/06/2017 11:45");DestinationObject dest = dozerBeanMapper.map(src, DestinationObject.class);System.out.println("DestinationObject : " + dest);}}

Вывод программы.

DestinationObject : DestinationObject [date=Sun Aug 06 11:45:00 IST 2017]

 

8. Пример Spring DozerBeanMapper

Если в вашем проекте есть фреймворк Spring, вы можете создать bean-компонент org.dozer.DozerBeanMapper и использовать его, как в примере ниже.

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="dozerBeanMapper" class="org.dozer.DozerBeanMapper"><property name="mappingFiles"><list><value>mappings/student-mapper.xml</value></list></property></bean></beans>

Как использовать DozerBeanMapper для картирования bean-компонентов.

package com.example.howtodoinjava.dozer.demo.withspring;import org.dozer.DozerBeanMapper;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.example.howtodoinjava.dozer.models.DestinationObject;import com.example.howtodoinjava.dozer.models.SourceObject;import com.example.howtodoinjava.dozer.models.Student;public class DemoWithDozerBeanMapper {public static void main(String[] args) {SourceObject sourceObject = new SourceObject();sourceObject.setName("Sajal");sourceObject.setAddress("India");sourceObject.getStudents().add(new Student("S1", "C1", "diffField1"));sourceObject.getStudents().add(new Student("S2", "C2", "diffField2"));sourceObject.getStudents().add(new Student("S3", "C3", "diffField3"));ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");DozerBeanMapper beanMapper =(DozerBeanMapper) applicationContext.getBean("dozerBeanMapper");DestinationObject destinationObject = beanMapper.map(sourceObject, DestinationObject.class);System.out.println(destinationObject);}}

Вывод программы.

DestinationObject [name=Sajal, address=India, pupils=[StudentVO [name=S1, batchName=C1, homeAddress=diffField1],StudentVO [name=S2, batchName=C2, homeAddress=diffField2],StudentVO [name=S3, batchName=C3, homeAddress=diffField3]]]

Обратите внимание, что Dozer успешно скопировал все поля из SourceObject в класс DestinationObject.

 

9. Резюме

Итак, в этом руководстве по dozer мы увидели, как можно настроить Dozer и как можно использовать Dozer для простого варианта использования. Мы также увидели, как создавать пользовательские конвертеры dozer, а также как можно объявлять сопоставления в стиле API с помощью BeanMappingBuilder.

Загрузить исходный код

Приятного обучения!!!

Прокрутить вверх