2017-01-11 3 views
0

У меня есть два экземпляра объекта Java, и я хочу объединить их значения в один экземпляр. Мне нужно выбрать, какой экземпляр объекта имеет приоритет, когда оба экземпляра объекта содержат значение для поля. Я также не хочу переопределять значения с нулевыми значениями.Как объединить два объекта java в один?

Пример:

MyClass source = new MyClass("source", 1, null); 
MyClass target = new MyClass("target", 2, "b"); 
merge(source, target); 
// target now has values ("source", 1, "b") 

Я использую Java 8 и Spring загрузки 1.4.1.

Редактировать: похоже, я не был ясен, поэтому добавил дополнительное описание. Кроме того, я уже предоставил свое собственное решение. Цель заключалась в том, чтобы внести вклад в это решение, когда другие имеют ту же проблему. Я нашел другие темы здесь, задавая тот же или похожий вопрос, но у них не было полного решения, как я опубликовал ниже.

+0

Это непонятный вопрос. В каком смысле сливаются? Вы можете объединить списки, по крайней мере, если они отсортированы, но я подозреваю, что у вас есть что-то другое в виду? –

+0

У меня есть объект A и Object B. У обоих есть поля String X, int Y, List Z. Я хочу скопировать все, а не нулевые поля в Object A в объект B. Это значит, что я могу объединить вход из двух источников в один последний объект, который нужно сохранить. – Chip

ответ

1

В библиотеке Spring-beans Spring есть класс org.springframework.beans.BeanUtils, который предоставляет метод copyProperties для копирования экземпляра исходного объекта в экземпляр целевого объекта. Однако он делает это только для полей первого уровня объекта. Вот мое решение, основанное на BeanUtils.copyProperties, для рекурсивного выполнения копии для каждого дочернего объекта, включая коллекции и карты.

package my.utility; 

import org.springframework.beans.BeanWrapper; 
import org.springframework.beans.BeansException; 
import org.springframework.beans.FatalBeanException; 
import org.springframework.util.Assert; 
import org.springframework.util.ClassUtils; 

import java.beans.PropertyDescriptor; 
import java.lang.reflect.Method; 
import java.lang.reflect.Modifier; 
import java.util.Arrays; 
import java.util.Collection; 
import java.util.List; 
import java.util.Map; 

/** 
* Created by cdebergh on 1/6/17. 
*/ 
public class BeanUtils extends org.springframework.beans.BeanUtils { 

    /** 
    * Copy the not null property values of the given source bean into the target bean. 
    * <p>Note: The source and target classes do not have to match or even be derived 
    * from each other, as long as the properties match. Any bean properties that the 
    * source bean exposes but the target bean does not will silently be ignored. 
    * <p>This is just a convenience method. For more complex transfer needs, 
    * consider using a full BeanWrapper. 
    * @param source the source bean 
    * @param target the target bean 
    * @throws BeansException if the copying failed 
    * @see BeanWrapper 
    */ 
    public static void copyPropertiesNotNull(Object source, Object target) throws BeansException { 
     copyPropertiesNotNull(source, target, null, (String[]) null); 
    } 

    private static void setAccessible(Method method) { 
     if (!Modifier.isPublic(method.getDeclaringClass().getModifiers())) { 
      method.setAccessible(true); 
     } 
    } 

    /** 
    * Copy the not null property values of the given source bean into the given target bean. 
    * <p>Note: The source and target classes do not have to match or even be derived 
    * from each other, as long as the properties match. Any bean properties that the 
    * source bean exposes but the target bean does not will silently be ignored. 
    * @param source the source bean 
    * @param target the target bean 
    * @param editable the class (or interface) to restrict property setting to 
    * @param ignoreProperties array of property names to ignore 
    * @throws BeansException if the copying failed 
    * @see BeanWrapper 
    */ 
    private static void copyPropertiesNotNull(Object source, Object target, Class<?> editable, 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); 

     for (PropertyDescriptor targetPropertyDescriptor : targetPds) { 
      Method targetWriteMethod = targetPropertyDescriptor.getWriteMethod(); 
      if (targetWriteMethod != null 
        && (ignoreList == null || !ignoreList.contains(targetPropertyDescriptor.getName()))) { 
       PropertyDescriptor sourcePropertyDescriptor = 
         getPropertyDescriptor(source.getClass(), targetPropertyDescriptor.getName()); 
       if (sourcePropertyDescriptor != null) { 
        Method sourceReadMethod = sourcePropertyDescriptor.getReadMethod(); 
        if (sourceReadMethod != null && 
          ClassUtils.isAssignable(
            targetWriteMethod.getParameterTypes()[0], sourceReadMethod.getReturnType())) { 
         try { 
          Method targetReadMethod = targetPropertyDescriptor.getReadMethod(); 
          setAccessible(sourceReadMethod); 
          setAccessible(targetWriteMethod); 
          Object sourceValue = sourceReadMethod.invoke(source); 

          if (sourceValue != null && targetReadMethod != null) { 
           setAccessible(targetReadMethod); 
           Object targetValue = targetReadMethod.invoke(target); 
           if (targetValue == null) { 
            targetWriteMethod.invoke(target, sourceValue); 
           } else if(targetValue instanceof Collection<?>) { 
            ((Collection) targetValue).addAll((Collection) sourceValue); 
           } else if (targetValue instanceof Map<?,?>) { 
            ((Map) targetValue).putAll((Map) sourceValue); 
           } else { 
            copyPropertiesNotNull(sourceValue, targetValue, editable, ignoreProperties); 
           } 
          } 
         } 
         catch (Throwable ex) { 
          throw new FatalBeanException(
            "Could not copy property '" + targetPropertyDescriptor.getName() + 
            "' from source to target", ex); 
         } 
        } 
       } 
      } 
     } 
    } 
}