본문 바로가기
Programming/SpringFramework

[Spring] BeanUtils copyProperties / Spring Framework에서 제공하는 bean들간의 작업을 도와주는 추상 클래스

by prinha 2020. 8. 31.
반응형

 

 

Static convenience methods for JavaBeans:

for instantiating beans, checking bean property types, copying bean properties, etc.

Mainly for use within the framework, but to some degree also useful for application classes

 

 

BeanUtils

스프링 프레임워크에서 제공하는 bean들간의 작업을 도와주는 추상 클래스

-> 주로 copying been properties에 사용됨


 

해당 포스팅에서는 copyProperties method에 대하여 알아보도록 하자

// public abstract class BeanUtils에서 copyProperties 관련 method

    public static void copyProperties(Object source, Object target) throws BeansException {
        copyProperties(source, target, (Class)null, (String[])null);
    }

    public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException {
        copyProperties(source, target, editable, (String[])null);
    }

    public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {
        copyProperties(source, target, (Class)null, ignoreProperties);
    }

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

    }

 

 

Spring을 사용하다가 class간 property를 복사해야할 경우에 해당 기능을 사용한다.

원시적인 방법으로는 setter method로 property를 하나 하나 복사하는 방법이 있으나,

이는 매우 비효율적이고 가독성 최악에 아주 아주 쓸데없는 짓이다.

특히나 접근해야 할 property가 수십, 수백개가 되는 상황이라면 이러한 방식은 멍청한 짓이 아닐 수 없다.

 

그래서 Spring에서 제공하는 BeanUtils를 이용하여 복사하는 방법을 사용한다.

 

해당 클래스를 그대로 복사해서 쓰는 방법을 사용하면 되지, 

왜 굳이 property를 복사하냐는 질문이 있을 수 있다.

여러 클래스들의 값을 가지고 비지니스 로직을 짜다보면 변경되어서는 안될 값들이 생긴다.

(collection에 들어가있는 값을 덮어쓰게 되면 문제가 발생할 수 있다.)

또한 필요한 property만 복사하여 쓰고 싶은 경우에 BeanUtils 메소드를 사용한다.

 

static 메소드 하나만 호출해도 아래와 같은 기능을 간단하게 사용할 수 있다.

// before
person2.setName(person1.getName());
person2.setAddress(person1.getAddress());
person2.setId(person1.getId());
person2.setPhone(person1.getPhone());

// after
// persion1의 property를 person2에 복사
BeanUtils.copyProperties(person1, person2);

 

모든 값이 아닌 필요한 property만 복사하고 싶은 경우에는

ignore할 property를 지정해주어 필요한 값만 복사한다.

아래와 같이 ignore 기능을 사용하면 "name"과 "phone"의 property는 복사하지 않는다.

BeanUtils.copyProperties(person1, person2, "name", "phone");

 



BeanUtils에는 copyProperty 목적 이외에도 여러가지 기능을 더 가지고 있는데, 해당 사이트를 참조하도록 하자

 

BeanUtils – Commons

Commons BeanUtils Most Java developers are used to creating Java classes that conform to the JavaBeans naming patterns for property getters and setters. It is natural to then access these methods directly, using calls to the corresponding getXxx and setXxx

commons.apache.org


참고 및 참조:https://gompangs.tistory.com/entry/JAVASpring-BeanUtils-%EA%B4%80%EB%A0%A8#footnote_link_119_1

 

반응형