编程知识 cdmana.com

Copyproperties property copy of BeanUtils

Deep copy and light copy

Simply put, copying is copying attributes from one class to another , about BeanUtils.copyProperties Come on , You have to make sure Property names are the same Of , Because it's based on get and set Method .

Shallow copy It can be understood that if it is a reference type , Then the target object copies only the address of the source object , Whether the target object or the source object changes , They all change together .

Deep copy Is to copy all the attributes of the target object to the source object , After copying, they are separated , It doesn't matter , Neither the source object nor the target object has any effect on the other .

Whether it's a shallow copy or a deep copy , For basic types and String It has no effect on , The only thing that matters is reference type data

copyProperties Methods use

Personal understanding , Through the following code, you may start to think like me , online The definition of deep and shallow copy is no problem Of , But for many ways , say The method is that there is a problem with deep and shallow copies Of . Let's look at the code !

public class BeanUtilsTest {

    public static void main(String[] args) {
        UserDto userDto = new UserDto();
        userDto.setName(" Zhang San ");
        userDto.setName("138888888888");
        AddressDto address = new AddressDto();
        address.setPhone("13888888111");
        address.setName(" Zhang Sansan ");
        address.setAddressDetail(" Beijing - haidian ");
        userDto.setAddress(address);

        UserDto userDto1 = new UserDto();
        BeanUtils.copyProperties(userDto, userDto1);

        System.out.println("userDto1.address.addressDetail" + userDto1.getAddress().getAddressDetail());
        address.setAddressDetail(" Beijing - The rising sun ");
        System.out.println();
        System.out.println("userDto.address.addressDetail" + userDto.getAddress().getAddressDetail());
        System.out.println("userDto1.address.addressDetail" + userDto1.getAddress().getAddressDetail());
    }
}

@Data
class UserDto {
    private String name;
    private String phone;
    private AddressDto address;
}

@Data
class AddressDto {
    private String name;
    private String phone;
    private String addressDetail;
}
 Copy code 

The output is as follows :

userDto1.address.addressDetail Beijing - haidian 

userDto.address.addressDetail Beijing - The rising sun 
userDto1.address.addressDetail Beijing - The rising sun 
 Copy code 

Source code analysis

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

    //  The goal is  class
    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;
    }
    // 1.  Get the target  Class  Property description for 
    PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
    List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

    // 2.  Loop traversal  class  Properties of 
    for (PropertyDescriptor targetPd : targetPds) {
        // Class  Attribute  set  Method , setXXX
        Method writeMethod = targetPd.getWriteMethod();
        // 3. If there is a writing method , And the attribute does not ignore , Keep going down , Otherwise skip and continue traversing 
        if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
            // 4. Get source Class The description of the property with the same name as the target attribute 
            PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
            // 5. If the source property description does not exist, skip directly , Otherwise keep going down 
            if (sourcePd != null) {
                //  Get the reading method of the source property description 
                Method readMethod = sourcePd.getReadMethod();
                // 6. If the read prevention described by the source property exists and the input parameter type of the return data type and the target property is the same or derived 
                //  Keep going down , Otherwise, skip and continue to traverse next time 
                if (readMethod != null) {
                    ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
                    ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);

                    // Ignore generic types in assignable check if either ResolvableType has unresolvable generics.
                    //  If any ResolvableType Has a generic type that cannot be resolved , It ignores assignable check Generic types in .
                    boolean isAssignable =
                        (sourceResolvableType.hasUnresolvableGenerics() || targetResolvableType.hasUnresolvableGenerics() ?
                         ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()) :
                         targetResolvableType.isAssignableFrom(sourceResolvableType));
                    
                    if (isAssignable) {
                        try {
                            //  If the source property read method modifier is not public, So change it to accessible 
                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
                                readMethod.setAccessible(true);
                            }
                            Object value = readMethod.invoke(source);
                            //  If the write method modifier for the target property is not public, To be accessible 
                            if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
                                writeMethod.setAccessible(true);
                            }
                            // 8. Assign the value of the source property to the target property by reflection 
                            writeMethod.invoke(target, value);
                        }
                        catch (Throwable ex) {
                            throw new FatalBeanException(
                                "Could not copy property '" + targetPd.getName() + "' from source to target", ex);
                        }
                    }
                }
            }
        }
    }
}
 Copy code 

Because this method reconstructs an object through reflection , Therefore, no matter what parameter value already exists in the original target object , Will be overwritten by the parameters of the new object to be copied .

We can also see that , During the copying of attributes , There is no special treatment , Properties of reference type , that BeanUtils.copyProperties The essence is to realize shallow copy .

版权声明
本文为[North of Xincheng]所创,转载请带上原文链接,感谢
https://cdmana.com/2022/134/202205141227436710.html

Scroll to Top