Java对象属性映射-对象复制-bean复制

目录

MapStruct

pom文件

代码

问题

framework cglib

代码

问题


使用任何已有的工具,都没有直接使用 get set 方式进行,对象转换的速度快,虽然get set 方式代码对一些比较麻烦,但是效率要高一些的。

推荐使用 MapStruct 方式。

图片

 

MapStruct

pom文件

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
            <version>1.9.4</version>
        </dependency>


        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.2.0.Final</version>
        </dependency>

        <!-- dozer使用时需要配置xml 文件,不推荐使用性能和 BeanUtils 差不多,使用过程可以参考 https://www.jianshu.com/p/bf8f0e8aee23-->
        <!-- https://mvnrepository.com/artifact/net.sf.dozer/dozer -->
        <!--<dependency>
            <groupId>net.sf.dozer</groupId>
            <artifactId>dozer</artifactId>
            <version>5.5.1</version>
        </dependency>-->

 

代码

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Created by yangLongFei on 2021/5/11 10:44
 * Version: $
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName
public class Student {
    private Integer id;
    private String name;
    private String age;
    private String phone;
    private String address;
}

import lombok.Data;
import java.io.Serializable;

/**
 * Created by yangLongFei on 2021/5/11 10:51
 * Version: $
 */
@Data
public class StudentDTO implements Serializable {
    private static final long serialVersionUID = 735190899850778343L;
    private Integer id;
    private String name;
    private String age;
    private String phone;
    private String address;
}

import lombok.Data;
import java.io.Serializable;

/**
 * Created by yangLongFei on 2021/5/11 16:59
 * Version: $
 */
@Data
public class StudentVO implements Serializable {
    private static final long serialVersionUID = 2059190505074790405L;

    private Integer pk;
    private String userName;
    private String userAge;
    private String userPhone;
    private String userAddress;
}

接口⭐️⭐️⭐️⭐️⭐️


import com.sys.yang.dto.StudentDTO;
import com.sys.yang.entity.Student;
import com.sys.yang.vo.StudentVO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

@Mapper
public interface ConverterStudent {

    ConverterStudent INSTANCE = Mappers.getMapper(ConverterStudent.class);

    @Mappings({
            @Mapping(source = "name", target = "name"),
            @Mapping(source = "age", target = "age")
    })
    StudentDTO entityToDTO(Student student);

    @Mappings({
            @Mapping(source = "id", target = "pk"),
            @Mapping(source = "name", target = "userName"),
            @Mapping(source = "age", target = "userAge"),
            @Mapping(source = "phone", target = "userPhone"),
            @Mapping(source = "address", target = "userAddress")
    })
    StudentVO dtoToVo(StudentDTO studentDTO);

}

测试类 


import com.sys.yang.dto.StudentDTO;
import com.sys.yang.entity.Student;
import com.sys.yang.vo.StudentVO;
import org.junit.Test;
import org.springframework.beans.BeanUtils;
import java.lang.reflect.Method;

/**
 * 对象转换,映射
 * 方式1:效率最高 get set 方法
 * 方式2:Common包 BeanUtils.copyProperties 反射的方式进行
 * 方式3:mapstruct 推荐使用,操作不复杂,效率和 get set 方式相差不大
 *
 * <p>
 * Created by yangLongFei on 2021/5/11 10:43
 * Version: $
 */
public class AToB {

    /**
     * set get 的时候使用
     * 生成 对象的set方法
     */
    public static void main(String[] args) {
        Class<StudentDTO> clazz = StudentDTO.class;
        Method[] fields = clazz.getDeclaredMethods();
        for (Method field: fields) {
            String name = field.getName();
            if(!name.startsWith("is") && !name.startsWith("get")){
                System.out.println("entity." + name + "()");
            }
        }
    }

    /**
     * 测试方法
     */
    @Test
    public void test1() {
        Student student = new Student(1,"zhagnsan","18","110112113114","diqiu");
        System.out.println(student.toString());

        StudentDTO studentDTO1 = new StudentDTO();
        BeanUtils.copyProperties(student,studentDTO1);
        System.out.println("BeanUtils: "+ studentDTO1.toString());

        StudentDTO studentDTO2 = ConverterStudent.INSTANCE.entityToDTO(student);
        System.out.println("mapstruct: entityToDTO " + studentDTO2.toString());

        StudentVO studentVO = ConverterStudent.INSTANCE.dtoToVo(studentDTO2);
        System.out.println("mapStruct: dtoToVo "+ studentVO);

    }

}

生成的接口文件

问题

执行测试代码的时候可能会出现异常

java: Internal error in the mapping processor: java.lang.NullPointerException  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.createManifestUrl(DefaultVersionInformation.java:180)  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.openManifest(DefaultVersionInformation.java:151)  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.getLibraryName(DefaultVersionInformation.java:127)  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.getCompiler(DefaultVersionInformation.java:120)  	at org.mapstruct.ap.internal.processor.DefaultVersionInformation.fromProcessingEnvironment(DefaultVersionInformation.java:98)  	at org.mapstruct.ap.internal.processor.DefaultModelElementProcessorContext.<init>(DefaultModelElementProcessorContext.java:59)  	at org.mapstruct.ap.MappingProcessor.processMapperElements(MappingProcessor.java:222)  	at org.mapstruct.ap.MappingProcessor.process(MappingProcessor.java:162)  	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)  	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)  	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)  	at java.lang.reflect.Method.invoke(Method.java:498)  	at org.jetbrains.jps.javac.APIWrappers$1.invoke(APIWrappers.java:255)  	at lombok.launch.AnnotationProcessorHider$AnnotationProcessor.process(Unknown Source)  	at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:794)  	at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:705)  	at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1800(JavacProcessingEnvironment.java:91)  	at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1035)  	at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1176)  	at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1170)  	at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:856)  	at com.sun.tools.javac.main.Main.compile(Main.java:523)  	at com.sun.tools.javac.api.JavacTaskImpl.doCall(JavacTaskImpl.java:129)  	at com.sun.tools.javac.api.JavacTaskImpl.call(JavacTaskImpl.java:138)  	at org.jetbrains.jps.javac.JavacMain.compile(JavacMain.java:231)  	at org.jetbrains.jps.incremental.java.JavaBuilder.lambda$compileJava$2(JavaBuilder.java:514)  	at org.jetbrains.jps.incremental.java.JavaBuilder.invokeJavac(JavaBuilder.java:560)  	at org.jetbrains.jps.incremental.java.JavaBuilder.compileJava(JavaBuilder.java:512)  	at org.jetbrains.jps.incremental.java.JavaBuilder.compile(JavaBuilder.java:355)  	at org.jetbrains.jps.incremental.java.JavaBuilder.doBuild(JavaBuilder.java:280)  	at org.jetbrains.jps.incremental.java.JavaBuilder.build(JavaBuilder.java:234)  	at org.jetbrains.jps.incremental.IncProjectBuilder.runModuleLevelBuilders(IncProjectBuilder.java:1464)  	at org.jetbrains.jps.incremental.IncProjectBuilder.runBuildersForChunk(IncProjectBuilder.java:1101)  	at org.jetbrains.jps.incremental.IncProjectBuilder.buildTargetsChunk(IncProjectBuilder.java:1247)  	at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunkIfAffected(IncProjectBuilder.java:1066)  	at org.jetbrains.jps.incremental.IncProjectBuilder.buildChunks(IncProjectBuilder.java:832)  	at org.jetbrains.jps.incremental.IncProjectBuilder.runBuild(IncProjectBuilder.java:419)  	at org.jetbrains.jps.incremental.IncProjectBuilder.build(IncProjectBuilder.java:183)  	at org.jetbrains.jps.cmdline.BuildRunner.runBuild(BuildRunner.java:132)  	at org.jetbrains.jps.cmdline.BuildSession.runBuild(BuildSession.java:301)  	at org.jetbrains.jps.cmdline.BuildSession.run(BuildSession.java:132)  	at org.jetbrains.jps.cmdline.BuildMain$MyMessageHandler.lambda$channelRead0$0(BuildMain.java:219)  	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)  	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)  	at java.lang.Thread.run(Thread.java:748)  

解决方式,添加编译参数 

-Djps.track.ap.dependencies=false

 

framework cglib

要转换的对象的,字段名称 要和 原对象的字段名称一致,否则赋值会失败,可以手动 convert 方法,但是,实现后所有的转换内容都会走 convert 方法

代码


import lombok.Data;

import java.io.Serializable;

/**
 * Created by yangLongFei on 2021/5/11 16:59
 * Version: $
 */
@Data
public class StudentVO implements Serializable {
    private static final long serialVersionUID = 2059190505074790405L;

    private Integer pk;
    private String userName;
    private String userAge;
    private String userPhone;
    private String userAddress;

    // framework cglib 使用到的内容
    private String id;
    private String name;
    private Integer age;
    private String phone;
    private String address;

}

convert 实现类


import org.springframework.cglib.core.Converter;

/**
 * Created by yangLongFei on 2021/5/11 19:53
 * Version: $
 */
public class ConvertStudentDtoToVo implements Converter {

    /**
     * ⭐️⭐️⭐️⭐️⭐️ 要转换的属性名称,相同的情况下,才会走该方法
     * @param o 原对象属性值,value
     * @param aClass 目标对象属性 类型,class java.lang.String
     * @param o1 目标对象属性set方法,setAddress
     * @return
     */
    @Override
    public Object convert(Object o, Class aClass, Object o1) {
        if (o.getClass().equals(aClass)) {
            return o;
        } else {
            if (o instanceof Integer) {
                return String.valueOf(o);
            }
            if (String.valueOf(o1).contains("Age")) {
                return Integer.valueOf(o.toString());
            }
            return o;
        }
    }

}

测试方法

    @Test
    public void test2() {
        Student student = new Student(1,"zhagnsan","18","110112113114","diqiu");

        // false 表示不使用 转换器,
        BeanCopier entityToDto = BeanCopier.create(Student.class, StudentDTO.class, false);
        StudentDTO studentDTO3 = new StudentDTO();
        // null 表示,不指定转换器,要使用转换器的化,需要实现 Converter 接口
        // 属性名称之间不能指定映射关系,当属性名称不同的时候赋值操作会失败
        entityToDto.copy(student, studentDTO3, null);
        System.out.println("cglib :entityToDTO " + studentDTO3.toString());

        BeanCopier dtoTOVo = BeanCopier.create(StudentDTO.class, StudentVO.class, false);
        StudentVO studentVO1 = new StudentVO();
        dtoTOVo.copy(studentDTO3, studentVO1, null);
        System.out.println("cglib: dtoToVo " + studentVO1.toString());

        // 一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性
        BeanCopier dtoTOVo2 = BeanCopier.create(StudentDTO.class, StudentVO.class, true);
        StudentVO studentVO2 = new StudentVO();
        dtoTOVo2.copy(studentDTO3, studentVO2, new ConvertStudentDtoToVo());
        System.out.println("cglib : convert "+studentVO2.toString());

    }

 

问题

beanUtils  不会进行 属性 类型的转换,如果字段名称相同,类型不同,不会对该字段进行赋值操作,( 测试方法中使用的 是 org.springframework.beans.BeanUtils )

cglib  在不定义Converter 的情况下也会出现 类型转换错误的异常,可以手动自定义转换器 convert ,一旦使用Converter,BeanCopier只使用Converter定义的规则去拷贝属性,所以在convert方法中要考虑所有的属性。

springframwork 有实现 cglib 的BeanCopier 不需要再引用 org.easymock 依赖

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值