Java Comparing Two objects Field by Field

Comparing two Java Objects using reflections.

package com.vivek.references;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

public class CompareFields {
	private static final Logger logger = LoggerFactory.getLogger(CompareFields.class);
	
	private CompareFields() {}

	public static  Map> compareFields(T source, T target) throws IllegalAccessException, InvocationTargetException {
		Map> result = new HashMap<>();

		if (source == null || target == null)
			return null;

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

		for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
			Method readMethod = propertyDescriptor.getReadMethod();

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

				Object targetValue = readMethod.invoke(target);
				Object sourceValue = readMethod.invoke(source);

				if (targetValue == null && sourceValue == null) {
					continue;
				}
				if (targetValue == null || !targetValue.equals(sourceValue)) {
					result.put(propertyDescriptor.getName(), new Pair(sourceValue, targetValue));
				}
			} 
		}

		return result;
	}
	
	public static class Pair {
		public T source;
		public U target;

		public Pair(T first, U second) {
			this.source = first;
			this.target = second;
		}

		@Override
		public String toString() {
			return "Pair [source=" + source + ", target=" + target + "]";
		}
	}
	
	@Setter
	@Getter
	@ToString
	static class Parent {
		private String var1;
		private int var2;
	}
	
	@Setter
	@Getter
	@ToString
	static class Child extends Parent {
		private String var3;
		private int var4;
	}

	public static void main(String[] args) throws IllegalAccessException, InvocationTargetException {
		Child one = new Child();
		
		one.setVar1("Var1");
		one.setVar2(1);
		one.setVar3("Var3");
		one.setVar4(2);
		
		Child two = new Child();
		
		two.setVar1("Var1");
		two.setVar2(1);
		two.setVar3("Var3");
		two.setVar4(2);
		
		Map> compareFields = compareFields(one, two);
		
		StringBuilder builder = new StringBuilder(System.lineSeparator());
		
		compareFields.entrySet().stream().map(entry -> entry.getKey() + " => " + entry.getValue().toString())
		.forEach(val -> builder.append(val).append(System.lineSeparator()));
		
		logger.info("Compare 1 - {}", builder);
		
		two.setVar1(null);
		two.setVar4(5);
		
		compareFields = compareFields(one, two);
		builder.setLength(0);
		builder.append(System.lineSeparator());
		
		compareFields.entrySet().stream().map(entry -> entry.getKey() + " => " + entry.getValue().toString())
		.forEach(val -> builder.append(val).append(System.lineSeparator()));
		
		logger.info("Compare 2 - {}", builder);
	}

}


Result :
INFO [com.vivek.references.CompareFields][main] - Compare 1 - 

INFO [com.vivek.references.CompareFields][main] - Compare 2 - 
var4 => Pair [source=2, target=5]
var1 => Pair [source=Var1, target=null]


Comments

Popular Posts