Merge/Copy properties using reflection in Java

There is already build in function in org.springframework.beans.BeanUtils.copyProperties which you can use to copy properties. But if want some customisation or need simpler one you can use below method :

This method also merge the collection if found.

package com.vivek.references.spring.example.common.reference;

import java.beans.IntrospectionException;
import java.beans.Introspector;
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.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

public class MergeProperties {
 private static final Logger logger = LoggerFactory.getLogger(MergeProperties.class);
 
 @Setter
 @Getter
 @NoArgsConstructor
 @AllArgsConstructor
 @ToString
 static class Parent {
  private String name;
  private String id;
 }

 @Setter
 @Getter
 @NoArgsConstructor
 @AllArgsConstructor
 @Builder
 @ToString(callSuper = true)
 static class Child extends Parent {
  private String var1;
  private String var2;
  private int version;
  private Set valueSet;
 }
 
 @SuppressWarnings("unchecked")
 private static  void copyMissingValues(T source, T target) {
  if (source == null || target == null) return;

  PropertyDescriptor[] propertyDescriptors;
  try {
   propertyDescriptors = Introspector.getBeanInfo(target.getClass()).getPropertyDescriptors();
  } catch (IntrospectionException e) {
   return;
  }

  for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
   Method writeMethod = propertyDescriptor.getWriteMethod();

   if (Objects.nonNull(writeMethod)) {
    Method readMethod = propertyDescriptor.getReadMethod();

    if (Objects.nonNull(readMethod)) {
     try {
      if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
       readMethod.setAccessible(true);
      }
      Object value = readMethod.invoke(target);

      if (Objects.isNull(value) || value.toString().isEmpty() || value.toString().equals("0")) {
       value = readMethod.invoke(source);

       if (Objects.nonNull(value)) {
        if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
         writeMethod.setAccessible(true);
        }

        writeMethod.invoke(target, value);
       }
      } else if (Collection.class.isAssignableFrom(propertyDescriptor.getPropertyType())) {
       // merge collection
       Collection sourceValues = (Collection)readMethod.invoke(source);
       
       if (Objects.nonNull(sourceValues)) {
        Collections.addAll((Collection)value, sourceValues.toArray());
       }
      }
     }
     catch (Throwable ex) {
      logger.error("{}", ex);
     }
    }
   }
  }
 }

 public static void main(String[] args) throws IntrospectionException {
  Child child1 = new Child();

  child1.setId("40");
  child1.setName("A");
  child1.setVar1("Value 1");
  child1.setVar2("10");
  child1.setVersion(1);
  child1.setValueSet(new HashSet<>(Arrays.asList("A", "B", "C")));

  Child child2 = new Child();

  child2.setName("B");
  child2.setVar2("50");
  child2.setValueSet(new HashSet<>(Arrays.asList("D", "E", "C")));

  MergeProperties.copyMissingValues(child1, child2);

  logger.info("{}", child2);
 }
}

Comments

Popular Posts