Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to compare two objects and find the fields/properties changed?

Tags:

java

I need to write some generic solution to find out what properties in two objects have changed and return the changed properties (not the value).

class Student {
    public String name;
    public Address address;
    public int age;
}

class Address {
    public String hno;
    public String street;
    public int pin;
}

public class Test {
    public static void main(String... arg) {

        Student s1 = new Student();
        s1.name = "Krishna";
        s1.age = 30;
        s1.address = new Address();
        s1.address.hno = "2-2-22";
        s1.address.street = "somewhere";
        s1.address.pin = 123;

        Student s2 = new Student();
        s2.name = "Krishna";
        s2.age = 20;
        s2.address = new Address();
        s2.address.hno = "1-1-11";
        s2.address.street = "nowhere";
        s2.address.pin = 123;

        List<String> = difference(s1, s2);
        // expected result
        // Student.age
        // Student.address.hno
        // Student.address.street
    }
}

Can anyone please suggest some solution?

PS

Overriding equals/hashcode is not an option for me.

I have written the below code but I am not sure how to identify if a type is complex (for example Address)

private static List<String> difference(Student s1, Student s2) throws IllegalArgumentException, IllegalAccessException {

        for(Field field: Student.class.getDeclaredFields()) {
            System.out.println(field.getName() + " " +field.get(s1).equals(field.get(s2)));
        }
        return null;
    }
like image 888
Krishna Chaitanya Avatar asked Jan 18 '18 13:01

Krishna Chaitanya


People also ask

Which of the methods are used to compare two objects based on their fields or state?

We use the hashcode() method to optimize performance when comparing objects. Executing hashcode() returns a unique ID for each object in your program, which makes the task of comparing the whole state of the object much easier.

Which method is used to compare the contents of two objects?

The equals() method of the Object class compare the equality of two objects. The two objects will be equal if they share the same memory address. Syntax: public boolean equals(Object obj)

How do I compare two fields of objects in Java?

reflect. Field is used to compare two field objects. This method compares two field objects and returns true if both objects are equal otherwise false. The two Field objects are considered equal if and only if when they were declared by the same class and have the same name and type.

Can you use == to compare objects?

Comparing Objects ¶ When using the comparison operator ( == ), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with == ), and are instances of the same class.


1 Answers

This is an enhancement of Dumbo's difference method, using recursion to check all nested complex fields.

    private static void difference(Object s1, Object s2, List<String> changedProperties, String parent) throws IllegalAccessException {
        for (Field field : s1.getClass().getDeclaredFields()) {
            if (parent == null) {
                parent = s1.getClass().getSimpleName();
            }
            field.setAccessible(true);
            Object value1 = field.get(s1);
            Object value2 = field.get(s2);
            if (value1 == null && value2 == null) {
                continue;
            }
            if (value1 == null || value2 == null) {
                changedProperties.add(parent + "." + field.getName());
            } else {
                if (isBaseType(value1.getClass())) {
                    if (!Objects.equals(value1, value2)) {
                        changedProperties.add(parent + "." + field.getName());
                    }
                } else {
                    difference(value1, value2, changedProperties, parent + "." + field.getName());
                }
            }
        }
    }

    private static final Set<Class> BASE_TYPES = new HashSet(Arrays.asList(
            String.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Void.class));
    public static boolean isBaseType(Class clazz) {
        return BASE_TYPES.contains(clazz);
    }

Sample usage (assumes the referenced model objects have getters/setters):

    public static void main(String[] args) throws IllegalAccessException {
        Student s1 = new Student();
        s1.setName("Krishna");
        s1.setAge(30);
        Address address = new Address();
        s1.setAddress(address);
        s1.getAddress().setHno("2-2-22");
        s1.getAddress().setStreet("somewhere");
        s1.getAddress().setPin(123);

        Student s2 = new Student();
        s2.setName("Krishna");
        s2.setAge(20);
        address = new Address();
        s2.setAddress(address);
        s2.getAddress().setHno("1-1-11");
        s2.getAddress().setStreet("nowhere");
        s2.getAddress().setPin(123);
        List<String> changedProperties = new ArrayList<>();

        difference(s1, s2, changedProperties, null);
        System.out.println("changedProperties = " + changedProperties);
        // expected result
        // Student.age
        // Student.address.hno
        // Student.address.street
    }

Result:

changedProperties = [Student.address.hno, Student.address.street, Student.age]

Primitive adapting checking adapted from https://stackoverflow.com/a/711226/1527469

like image 89
awgtek Avatar answered Sep 24 '22 09:09

awgtek