zoukankan      html  css  js  c++  java
  • JavaBean中对象的复制:BeanUtils和Dozer

    在开发过程中,我们会遇到各种bean之间的转换,比如用ORM框架查询出来的数据,对应的bean,需要转换成Dto返回给调用方,这个时候就需要进行bean的转换了

    一、org.springframework.beans.BeanUtils

    BeanUtils是开发中常用到的工具类,而获取这一工具类主要是通过导入org.springframework.beans.BeanUtils或者org.apache.commons.beanutils.BeanUtils包来获取,但是不同的包中BeanUtils的方法使用是不一样的,接下来就对这两个包中的copyProperties方法进行对比。
    先来看一下这两个包中的copyProperties方法的定义:

    //org.springframework.beans.BeanUtils
    public static void copyProperties(Object source, Object target){....}
    
    //org.apache.commons.beanutils.BeanUtils
    public static void copyProperties(Object dest,Object orig){....}

    由定义可知,在org.springframework.beans.BeanUtils包下的copyProperties第一个参数是被copy的对象,而org.apache.commons.beanutils.BeanUtils中是第二个参数,所以使用时不要弄混。

    建议使用org.springframework.beans.BeanUtils包下的copyProperties,因为目标对象(target/dest)中不包含被copy的对象(source/orig)的所有字段时,apache包下的BeanUtils会报错。

    源代码:

    private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {
            Assert.notNull(source, "Source must not be null");
            Assert.notNull(target, "Target must not be null");
            Class<?> actualEditable = target.getClass();
            if (editable != null) {
                if (!editable.isInstance(target)) {
                    throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
                }
    
                actualEditable = editable;
            }
    
            PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
            List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
            PropertyDescriptor[] var7 = targetPds;
            int var8 = targetPds.length;
    
            for(int var9 = 0; var9 < var8; ++var9) {
                PropertyDescriptor targetPd = var7[var9];
                Method writeMethod = targetPd.getWriteMethod();
                if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
                    PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
                    if (sourcePd != null) {
                        Method readMethod = sourcePd.getReadMethod();
                        if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
                            try {
                                if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                    readMethod.setAccessible(true);
                                }
    
                                Object value = readMethod.invoke(source);  // 将源对象的key对应的值读取出来
                                if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                    writeMethod.setAccessible(true);
                                }
    
                                writeMethod.invoke(target, value); // 将源对象的值赋值到目标对象中
                            } catch (Throwable var15) {
                                throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15);
                            }
                        }
                    }
                }
            }
    
        }

    注意:复制的是属性,而不是字段,故要加@Data注解

    1、当目标对象中包含源对象的所有属性时,会将源对象的所有属性值都复制过来

    Student类

    @Data
    public class Student {
        private String id;
        private String username;
        private Integer age;
    }

    StudentDTO

    @Data
    public class StudentDTO{
        private String id;
        private String username;
        private Integer age;
        private String gender;
        private Date birthday;
    }

    测试

    public class BeanUtilsTest {
        public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, IntrospectionException {
            Student student = new Student();
            student.setId(UUID.randomUUID().toString());
            student.setUsername("张三");
            student.setAge(22);
            StudentDTO studentDTO = new StudentDTO();
            BeanUtils.copyProperties(student,studentDTO);
            System.out.println(studentDTO);
        }
    }

    结果:

    StudentDTO(id=4b44fd85-1f06-4395-988f-628173f13480, username=张三, age=22, gender=null, birthday=null)

     2、当目标对象不包含源对象的所有属性时,源对象的部分属性值会丢失

    Student类

    @Data
    public class Student {
        private String id;
        private String username;
        private Integer age;
    }

    StudentDTO

    @Data
    public class StudentDTO{
        private String id;
        private String username;
    }

    测试

    public class BeanUtilsTest {
        public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, IntrospectionException {
            Student student = new Student();
            student.setId(UUID.randomUUID().toString());
            student.setUsername("张三");
            student.setAge(22);
            StudentDTO studentDTO = new StudentDTO();
            BeanUtils.copyProperties(student,studentDTO);
            System.out.println(studentDTO);
        }
    }

    结果:

    StudentDTO(id=4fc2e73c-3ba5-448d-8884-88f3c66bbed7, username=张三)

    3、当源对象和目标对象中的属性的类型不一样时,会报错

    Student类

    @Data
    public class Student {
        private String id;
        private String username;
        private Integer age;
    }

    StudentDTO类

    @Data
    public class StudentDTO extends Student{
        private String id;
        private String username;
        private Long age;
    }

    注意:两个类的age属性的类型不一样,一个为Integer,一个为Long

    测试

    public class BeanUtilsTest {
        public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, IntrospectionException {
            Student student = new Student();
            student.setId(UUID.randomUUID().toString());
            student.setUsername("张三");
            student.setAge(22);
            StudentDTO studentDTO = new StudentDTO();
            BeanUtils.copyProperties(student,studentDTO);
            System.out.println(studentDTO);
        }
    }

    结果

    Error:(16, 18) java: com.ljxx.entity.business.StudentDTO中的getAge()无法覆盖com.ljxx.entity.business.Student中的getAge()
      返回类型java.lang.Long与java.lang.Integer不兼容

    综上所述:BeanUtils.copyProperties只能复制对象中名称且类型相同的属性。对于类型不同或者名称不同时,无法完成复制。而下面将要讲述的Dozer则能很好的解决该问题。

    二、Dozer

    Dozer是什么?

    Dozer是一个JavaBean映射工具库。

    它支持简单的属性映射,复杂类型映射,双向映射,隐式显式的映射,以及递归映射。

    它支持三种映射方式:注解、API、XML。

    Dozer的配置

    为什么要有映射配置?

    如果要映射的两个对象有完全相同的属性名,那么一切都很简单。

    只需要直接使用Dozer的API即可:

    Mapper mapper = new DozerBeanMapper();
    DestinationObject destObject = mapper.map(sourceObject, DestinationObject.class);

    但实际映射时,往往存在属性名不同的情况。

    所以,你需要一些配置来告诉Dozer应该转换什么,怎么转换。

    映射配置文件

    src/test/resources目录下添加dozer/dozer-mapping.xml文件。

    <mapping>标签中允许你定义<class-a><class-b>,对应着相互映射的类。

    <field>标签里定义要映射的特殊属性。需要注意<a><class-a>对应,<b><class-b>对应,聪明的你,猜也猜出来了吧。

    <?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.net
              http://dozer.sourceforge.net/schema/beanmapping.xsd">
      <mapping date-format="yyyy-MM-dd">
        <class-a>org.zp.notes.spring.common.dozer.vo.NotSameAttributeA</class-a>
        <class-b>org.zp.notes.spring.common.dozer.vo.NotSameAttributeB</class-b>
        <field>
          <a>name</a>
          <b>value</b>
        </field>
      </mapping>
    </mappings>

    Dozer把对象中名称相同的属性进行复制,对于名称不相同或类型不一样,则可以在xml中进行定义。

    新建一个springboot工程

    1、依赖

    <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.0.1.RELEASE</version>
        </parent>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.16</version>
            </dependency>
            <dependency>
                <groupId>com.github.dozermapper</groupId>
                <artifactId>dozer-spring-boot-starter</artifactId>
                <version>6.5.2</version>
            </dependency>
        </dependencies>

    2、在application.properties中配置如下:

    server.port=8002
    dozer.mapping-files=classpath:dozer/dozer-config.xml

    3、启动类

    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class, args);
        }
    }

    4、如果两个类的属性名和类型完全一样

    注意:此时不需要进行映射,即不需要doze-config.xml文件

    Student类

    @Data
    public class Student {
        private String id;
        private String name;
        private Integer age;
        private String birthday;
    }

    StudentDTO

    @Data
    public class StudentDTO{
        private String id;
        private String name;
        private Integer age;
        private String birthday;
    }

    StudentController

    @RestController
    public class StudentController {
        @Autowired
        private Mapper dozerMapper;
        @GetMapping("/student")
        public StudentDTO getInfo(){
            System.out.println("come");
            Student student = new Student();
            student.setId(UUID.randomUUID().toString());
            student.setName("张三");
            student.setAge(22);
            student.setBirthday("2020-06-22");
            StudentDTO studentDTO = dozerMapper.map(student,StudentDTO.class);
            System.out.println(studentDTO);
            return studentDTO;
        }
    }

    启动项目后访问http://localhost:8002/student,结果

    {"id":"3a8a7daa-600a-413d-9bab-189728701a7a","name":"张三","age":22,"birthday":"2020-06-22"}

    5、如果源对象和目标对象的属性名一样,但是类型不一样

    修改StudentDTO类

    @Data
    public class StudentDTO{
        private String id;
        private String name;
        private Long age;
        private Date birthday;
    }

    将age由Integer改为Long,将birthday由String改为Date。如果只是将Integer改为Long,由于原型包装类和原型包装类之间可以自动转换,故不需要写dozer-config.xml文件,但是String类型与Date类型不能直接转换,故需要dozer-config.xml文件

    再次访问,报错如下:

    Caused by: java.lang.NumberFormatException: For input string: "2020-06-22"

    dozer-config.xml文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://dozermapper.github.io/schema/bean-mapping"
              xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                               http://dozermapper.github.io/schema/bean-mapping.xsd">
    
        <configuration>
            <date-format>yyyy-MM-dd</date-format>
        </configuration>
    </mappings>

    启动项目,再次访问,结果如下:

    {"id":"69a13efd-d112-4aac-8a9c-e7780bb5cb6f","name":"张三","age":22,"birthday":"2020-06-21T16:00:00.000+0000"}

    发现age已经转换成功,而birthday的样子有点怪。我们在StudentDTO中加@JsonFormat注解

    @Data
    public class StudentDTO{
        private String id;
        private String name;
        private Long age;
        @JsonFormat(pattern="yyyy-MM-dd",timezone="GMT+8")
        private Date birthday;
    }

    启动项目,再次访问,结果如下:

    {"id":"2d0e30a6-0f55-4629-bba4-2c2132eb7ec0","name":"张三","age":22,"birthday":"2020-06-22"}

    字符串和日期映射(String to Date Mapping)

    字符串在和日期进行映射时,允许用户指定日期的格式。

    格式的设置分为三个作用域级别:

    属性级别

    对当前属性有效(这个属性必须是日期字符串)

    <field>
      <a date-format="MM/dd/yyyy HH:mm:ss:SS">dateString</a>
      <b>dateObject</b>
    </field>

    类级别

    对这个类中的所有日期相关的属性有效

    <mapping date-format="MM-dd-yyyy HH:mm:ss">
      <class-a>org.dozer.vo.TestObject</class-a>
      <class-b>org.dozer.vo.TestObjectPrime</class-b>
      <field>
        <a>dateString</a>
        <b>dateObject</b>
      </field>
    </mapping>

    全局级别

    对整个文件中的所有日期相关的属性有效。

    <mappings>
      <configuration>
        <date-format>MM/dd/yyyy HH:mm</date-format>
      </configuration>
    
      <mapping wildcard="true">
        <class-a>org.dozer.vo.TestObject</class-a>
        <class-b>org.dozer.vo.TestObjectPrime</class-b>
        <field>
          <a>dateString</a>
          <b>dateObject</b>
        </field>
      </mapping>
    </mappings>

    6、如果源对象和目标对象的名称和类型均不一样

    修改StudentDTO

    @Data
    public class StudentDTO{
        private String userId;
        private String userName;
        private Long userAge;
        @JsonFormat(pattern="yyyy-MM-dd",timezone="GMT+8")
        private Date userBirthday;
    }

    在原来的属性名前均加上user,

    修改dozer-config.xml文件如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://dozermapper.github.io/schema/bean-mapping"
              xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                               http://dozermapper.github.io/schema/bean-mapping.xsd">
    
        <configuration>
            <date-format>yyyy-MM-dd</date-format>
        </configuration>
        <!--配置对象中属性的对应关系,相同的属性无需映射-->
        <mapping>
            <class-a>com.zwh.dozer.entity.Student</class-a>
            <class-b>com.zwh.dozer.entity.StudentDTO</class-b>
            <field>
                <a>id</a>
                <b>userId</b>
            </field>
            <field>
                <a>name</a>
                <b>username</b>
            </field>
            <field>
                <a>age</a>
                <b>userAge</b>
            </field>
            <field>
                <a>birthday</a>
                <b>userBirthday</b>
            </field>
        </mapping>
    
    </mappings>

    启动项目,再次访问,结果如下:

    {"userId":"36662d45-47c8-47ec-ba03-84564fab30c2","username":"张三","userAge":22,"userBirthday":"2020-06-22"}

    7、使用注解方式进行映射

    Dozer 5.3.2版本开始支持注解方式配置映射(只有一个注解:@Mapping)。可以应对一些简单的映射处理,复杂的就玩不转了。

    看一下@Mapping的声明就可以知道,这个注解只能用于元素和方法。

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.METHOD})
    public @interface Mapping {
      String value() default "";
    }

    注意:@Mapping注解只能写在源对象的实体类中

    修改Student类

    @Data
    public class Student {
        @Mapping("userId")
        private String id;
        @Mapping("username")
        private String name;
        @Mapping("userAge")
        private Integer age;
        @Mapping("userBirthday")
        private String birthday;
    }

    现在dozer-config.xml如下

    <?xml version="1.0" encoding="UTF-8"?>
    <mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://dozermapper.github.io/schema/bean-mapping"
              xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                               http://dozermapper.github.io/schema/bean-mapping.xsd">
    
        <configuration>
            <date-format>yyyy-MM-dd</date-format>
        </configuration>
    
    </mappings>

    启动项目,再次访问,结果如下:

    {"userId":"4df4dde9-567c-4665-9ced-f3f70bdd5a6c","username":"张三","userAge":22,"userBirthday":"2020-06-22"}

    8、配置文件使用通配符

    可以发现,如果有多个类进行映射,那么dozer-config.xml文件内容会很多,当然也可分文件映射。在dozer目录下新建user-dozer.xml,

    <?xml version="1.0" encoding="UTF-8"?>
    <mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://dozermapper.github.io/schema/bean-mapping"
              xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                               http://dozermapper.github.io/schema/bean-mapping.xsd">
    
        <!--配置对象中属性的对应关系,相同的属性无需映射-->
        <mapping>
            <class-a>com.zwh.dozer.entity.Student</class-a>
            <class-b>com.zwh.dozer.entity.StudentDTO</class-b>
            <field>
                <a>id</a>
                <b>userId</b>
            </field>
            <field>
                <a>name</a>
                <b>username</b>
            </field>
            <field>
                <a>age</a>
                <b>userAge</b>
            </field>
            <field>
                <a>birthday</a>
                <b>userBirthday</b>
            </field>
        </mapping>
    
    </mappings>

    此时dozer-config.xml内容如下

    <?xml version="1.0" encoding="UTF-8"?>
    <mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://dozermapper.github.io/schema/bean-mapping"
              xsi:schemaLocation="http://dozermapper.github.io/schema/bean-mapping
                               http://dozermapper.github.io/schema/bean-mapping.xsd">
    
        <configuration>
            <date-format>yyyy-MM-dd</date-format>
        </configuration>
    
    </mappings>

    配置文件

    server.port=8002
    dozer.mapping-files=classpath:dozer/*.xml

    dozer默认不支持通配符配置,故需编写配置类进行配置

    @Configuration
    public class DozerConfig {
    
        @Bean
        public DozerBeanMapperFactoryBean dozerMapper(@Value("${dozer.mapping-files}") Resource[] resources) throws IOException {
            DozerBeanMapperFactoryBean dozerBeanMapperFactoryBean = new DozerBeanMapperFactoryBean();
            dozerBeanMapperFactoryBean.setMappingFiles(resources);
            return dozerBeanMapperFactoryBean;
        }
    }

    启动项目,结果如下:

    {"userId":"e579ffcd-c5d6-4eb1-a27a-2c03e661cf81","username":"张三","userAge":22,"userBirthday":"2020-06-22"}

    三、Dozer扩展

    Dozer支持的数据类型转换

    Dozer可以自动做数据类型转换。当前,Dozer支持以下数据类型转换(都是双向的)

    • Primitive to Primitive Wrapper

      原型(int、long等)和原型包装类(Integer、Long)

    • Primitive to Custom Wrapper

      原型和定制的包装

    • Primitive Wrapper to Primitive Wrapper

      原型包装类和包装类

    • Primitive to Primitive

      原型和原型

    • Complex Type to Complex Type

      复杂类型和复杂类型

    • String to Primitive

      字符串和原型

    • String to Primitive Wrapper

      字符串和原型包装类

    • String to Complex Type if the Complex Type contains a String constructor

      字符串和有字符串构造器的复杂类型(类)

    • String to Map

      字符串和Map

    • Collection to Collection

      集合和集合

    • Collection to Array

      集合和数组

    • Map to Complex Type

      Map和复杂类型

    • Map to Custom Map Type

      Map和定制Map类型

    • Enum to Enum

      枚举和枚举

    • Each of these can be mapped to one another: java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar

      这些时间相关的常见类可以互换:java.util.Date, java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Calendar, java.util.GregorianCalendar

    • String to any of the supported Date/Calendar Objects.

      字符串和支持Date/Calendar的对象

    • Objects containing a toString() method that produces a long representing time in (ms) to any supported Date/Calendar object.

      如果一个对象的toString()方法返回的是一个代表long型的时间数值(单位:ms),就可以和任何支持Date/Calendar的对象转换。

    集合和数组映射(Collection and Array Mapping)

    Dozer可以自动处理以下类型的双向转换。

    • List to List
    • List to Array
    • Array to Array
    • Set to Set
    • Set to Array
    • Set to List

    全局配置(Global Configuration)

    全局配置用来设置全局的配置信息。此外,任何定制转换都是在这里定义的。

    全局配置都是可选的。

    • <date-format>表示日期格式
    • <stop-on-errors>错误处理开关
    • <wildcard>通配符
    • <trim-strings>裁剪字符串开关
    <configuration >
      
      <date-format>MM/dd/yyyy HH:mm</date-format>
      <stop-on-errors>true</stop-on-errors>
      <wildcard>true</wildcard>
      <trim-strings>false</trim-strings>
         
      <custom-converters> <!-- these are always bi-directional -->
        <converter type="org.dozer.converters.TestCustomConverter" >
          <class-a>org.dozer.vo.TestCustomConverterObject</class-a>
          <class-b>another.type.to.Associate</class-b>
        </converter>
         
      </custom-converters>     
    </configuration>

    全局配置的作用是帮助你少配置一些参数,如果个别类的映射规则需要变更,你可以mapping中覆盖它。

    覆盖的范例如下

    <mapping date-format="MM-dd-yyyy HH:mm:ss"> 
      <!-- 省略 -->
    </mapping>
    
    <mapping wildcard="false">
      <!-- 省略 -->
    </mapping> 
    
    <mapping stop-on-errors="false"> 
      <!-- 省略 -->
    </mapping>
    
    <mapping trim-strings="true"> 
      <!-- 省略 -->
    </mapping>      

    深度映射(Deep Mapping)

    所谓深度映射,是指允许你指定属性的属性(比如一个类的属性本身也是一个类)。举例来说

    Source.java

    public class Source {
        private long id;
        private String info;
    }

    Dest.java

    public class Dest {
        private long id;
        private Info info;
    }

    Info.java

    public class Info {
        private String content;
    }

    映射规则

    <mapping>
      <class-a>org.zp.notes.spring.common.dozer.vo.Source</class-a>
      <class-b>org.zp.notes.spring.common.dozer.vo.Dest</class-b>
      <field>
        <a>info</a>
        <b>info.content</b>
      </field>
    </mapping>

    排除属性(Excluding Fields)

    如何在做类型转换时,自动排除一些属性,Dozer提供了几种方法,这里只介绍一种比较通用的方法。

     field-exclude可以排除不需要映射的属性。

    <field-exclude> 
      <a>fieldToExclude</a> 
      <b>fieldToExclude</b> 
    </field-exclude>

    单向映射(One-Way Mapping)

    注:本文的映射方式,无特殊说明,都是双向映射的。

    有的场景可能希望转换过程不可逆,即单向转换。

    单向转换可以通过使用one-way来开启

    类级别

    <mapping type="one-way"> 
      <class-a>org.dozer.vo.TestObjectFoo</class-a>
      <class-b>org.dozer.vo.TestObjectFooPrime</class-b>   
        <field>
          <a>oneFoo</a>
          <b>oneFooPrime</b>
        </field>
    </mapping>  

    属性级别

    <mapping> 
      <class-a>org.dozer.vo.TestObjectFoo2</class-a>
      <class-b>org.dozer.vo.TestObjectFooPrime2</class-b>   
      <field type="one-way">
        <a>oneFoo2</a>
        <b>oneFooPrime2</b>
      </field>
    
      <field type="one-way">
        <a>oneFoo3.prime</a>
        <b>oneFooPrime3</b>
      </field>

    定制转换(Custom Converters)

    如果Dozer默认的转换规则不能满足实际需要,你可以选择定制转换。

    定制转换通过配置XML来告诉Dozer如何去转换两个指定的类。当Dozer转换这两个指定类的时候,会调用你的映射规则去替换标准映射规则。

    为了让Dozer识别,你必须实现org.dozer.CustomConverter接口。否则,Dozer会抛异常。

    具体做法:

    (1) 创建一个类实现org.dozer.CustomConverter接口。

    public class TestCustomConverter implements CustomConverter {
      
      public Object convert(Object destination, Object source, 
          Class destClass, Class sourceClass) {
        if (source == null) {
          return null;
        }
        CustomDoubleObject dest = null;
        if (source instanceof Double) {
          // check to see if the object already exists
          if (destination == null) {
            dest = new CustomDoubleObject();
          } else {
            dest = (CustomDoubleObject) destination;
          }
          dest.setTheDouble(((Double) source).doubleValue());
          return dest;
        } else if (source instanceof CustomDoubleObject) {
          double sourceObj = 
            ((CustomDoubleObject) source).getTheDouble();
          return new Double(sourceObj);
        } else {
          throw new MappingException("Converter TestCustomConverter "
              + "used incorrectly. Arguments passed in were:"
              + destination + " and " + source);
        }
      } 

    (2) 在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.net
              http://dozer.sourceforge.net/schema/beanmapping.xsd">
      <configuration>
        <!-- 总是双向转换的 -->
        <custom-converters>
          <converter type="org.dozer.converters.TestCustomConverter" >
            <class-a>org.dozer.vo.CustomDoubleObject</class-a>
            <class-b>java.lang.Double</class-b>
          </converter>
    
          <!-- You are responsible for mapping everything between 
               ClassA and ClassB -->
          <converter 
            type="org.dozer.converters.TestCustomHashMapConverter" >
            <class-a>org.dozer.vo.TestCustomConverterHashMapObject</class-a>
            <class-b>org.dozer.vo.TestCustomConverterHashMapPrimeObject</class-b>
          </converter>
        </custom-converters>     
      </configuration>
    </mappings>

    属性级

    <mapping>
      <class-a>org.dozer.vo.SimpleObj</class-a>
      <class-b>org.dozer.vo.SimpleObjPrime2</class-b>    
      <field custom-converter=
        "org.dozer.converters.TestCustomConverter">
        <a>field1</a>
        <b>field1Prime</b>
      </field>
    </mapping>  

    参考文档:https://www.cnblogs.com/aimei/p/12201238.html

     dozer官方文档:http://dozer.sourceforge.net/documentation/gettingstarted.html

  • 相关阅读:
    day26:面向对象进阶:set、get、del反射和内置
    day26、面向对象进阶:多态、封装、反射
    day25、 静态属性、类方法、静态方法、组合、继承、
    day24:面向对象设计与面向对象编程、类和对象
    day23:s
    day21、模块
    阿里云ECS服务器挂载磁盘
    Python爬虫总结——常见的报错、问题及解决方案
    Python爬虫实战——反爬机制的解决策略【阿里】
    Python爬虫实战——反爬策略之模拟登录【CSDN】
  • 原文地址:https://www.cnblogs.com/zwh0910/p/15353858.html
Copyright © 2011-2022 走看看