Stepping on the pit of BeanUtils.copyProperties deep object conversion and \ scheme

premise

After the layering is developed, objects need to be converted, such as request object to dto database object.

Manual object conversion, although the execution performance is high, the development efficiency is very low, and there may be omissions.

I recently encountered a bug when using BeanUtils.copyProperties. Stepping on the pit sample code:

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;
    }
}

main function

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");
    }
}

Let's see what happens.

 From the debug, we can know that the first object type obtained from ListB is actually A

 I didn't look at the source code carefully, let me call it shallow object property copying. The guess is that when copying List, generics are ignored.

solve

Now that this situation has occurred, there must be a solution. I saw the MapStruct framework under the recommendation, which is simple and easy to use. Simple use case:

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;
    }
}

The code is basically the same as the above code, only one more interface needs to be added. During compilation, MapStruct will generate an implementation of this interface. This implementation uses pure Java method calls to map between the source object and the target object, not the Java reflection mechanism.

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

main function

    /**
     * 参考: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"); // 完全没问题
    }

That's it.

In addition, MapStruct provides the IDEA MapStruct Support plug-in, so that we can use MapStruct more happily in IDEA 

How to use please Baidu. 

summary

Maybe BeanUtils.copyProperties has a solution, smart you remember to tell me.

If you make a mistake, add the following code to try

<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>

Guess you like

Origin blog.csdn.net/wai_58934/article/details/128619287