踩BeanUtils.copyProperties深度对象转换的坑以及\方案

前提

在开发分层之后,需要对对象进行转换,比如request请求对象转为dto数据库对象。

手动进行对象的转换,虽然执行性能很高,但是开发效率非常低下,且可能会存在漏写的情况。

最近在使用BeanUtils.copyProperties时遇到一个bug。踩坑示例代码:

public class A {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class B {
    private String age;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

public class ListA {
    private List<A> list;

    public List<A> getList() {
        return list;
    }

    public void setList(List<A> list) {
        this.list = list;
    }
}

public class ListB {
    private List<B> list;

    public List<B> getList() {
        return list;
    }

    public void setList(List<B> list) {
        this.list = list;
    }
}

主运行函数

public class BeanUtilsMain {
    public static void main(String[] args) {
        ListA listA = new ListA();
        ArrayList<A> list = new ArrayList<>();
        A a = new A();
        a.setName("kong");
        list.add(a);
        listA.setList(list);
        ListB listB = new ListB();
        BeanUtils.copyProperties(listA,listB);
        listB.getList().get(0).setAge("2");
    }
}

大家看看会出现什么问题。

 从debug可以知道从ListB中拿到的第一个对象类型竟然是A

 没仔细看源码,我且称它为浅对象属性复制吧。猜想是因为复制List时,忽视泛型了。

解决

既然出现这种情况了,那必然需要有个解决方案,在推荐之下看到了MapStruct这个框架,写法简单且好用。简单使用案例:

maven

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>1.5.3.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.5.3.Final</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok-mapstruct-binding</artifactId>
            <version>0.2.0</version>
            <scope>provided</scope>
        </dependency>
public class A {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

public class B {
    private String age;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

public class ListA {
    private List<A> list;

    public List<A> getList() {
        return list;
    }

    public void setList(List<A> list) {
        this.list = list;
    }
}

public class ListB {
    private List<B> list;

    public List<B> getList() {
        return list;
    }

    public void setList(List<B> list) {
        this.list = list;
    }
}

代码与上边代码基本一致,只需要再新增一个接口。在编译过程中,MapStruct 将生成该接口的实现。此实现使用纯 Java 的方法调用源对象和目标对象之间进行映射,并非 Java 反射机制。

@Mapper
public interface Converter {
    Converter INSTANCE = Mappers.getMapper(Converter.class);
    ListB fromSource(ListA source);
    ListA toSource(ListB target);
}

主函数

    /**
     * 参考:https://www.jianshu.com/p/53aac78e7d60
     * @author liutong
     * @date 2023/1/5 11:35
     * @param args
     */
    public static void main(String[] args) {
        ListA listA = new ListA();
        ArrayList<A> list = new ArrayList<>();
        A a = new A();
        a.setName("kong");
        list.add(a);
        listA.setList(list);
        ListB listB = Converter.INSTANCE.fromSource(listA);
        listB.getList().get(0).setAge("2"); // 完全没问题
    }

至此结束。

另外MapStruct 提供了 IDEA MapStruct Support 插件,让我们在 IDEA 中,可以更愉快的使用 MapStruct 

如何使用请自行百度。 

小结

或许BeanUtils.copyProperties有解决方案,聪明的你记得告诉我。

如果使用出错,则添加以下代码试试

<build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <annotationProcessorPaths>
                        <!-- 引入 mapstruct-processor -->
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${mapstruct.version}</version>
                        </path>
                        <!-- 引入 lombok-processor -->
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                            <version>${lombok.version}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>

猜你喜欢

转载自blog.csdn.net/wai_58934/article/details/128619287