jasonfungsing
jasonfungsing

Reputation: 1655

Compare fields in two Object and update one to the other in Java

I have running into an issue to update existing data with whatever the changed made by user.

For example, I have one Company Object as below

public class Company {

    private String id;

    private String name;

    private String url;

    //Getter and setter.....
}

Now I have one company instance with data as below

Company company = new Company();
company.setId("id12345678");
company.setName("company Old Name");
company.setUrl("company Old Url");

Now user has create another company instance just to update the name and url of existing Company

Company newCompany = new Company();
newCompany.setId("id12345678");
newCompany.setName("company New Name");
newCompany.setUrl("company New Url");

As can see, the new instance of Company has the same Id as the old one but with different name and url.

Is there any Utility tools/library can simple find all the differences between those two object and apply the changes to the company instance? (don't really want to write code to manually compare each field)

Something like

company = AwesomeLibraryUtils.compareAndApplyDifferences(company, newCompany);

After this, the company instance remain the same id but with all the new values of name and url from newCompany instance.

Thanks.

Upvotes: 3

Views: 4645

Answers (3)

Asoub
Asoub

Reputation: 2371

There are no really utility that can "find and apply" the differences (as far as I know), however, there is reflection (as other said), like Apache Comparator (which is a powerfull class).

https://commons.apache.org/proper/commons-collections/javadocs/api-3.2.1/org/apache/commons/collections/ComparatorUtils.html

As for "applying differences", there is also a tool in Apache (BeanUtils this time): http://commons.apache.org/proper/commons-beanutils/ which is "copyProperties(Object o1, Object o2)" wihchi will copy all properties (fields) from one object to another.

So, you just have to compare the objects and if their are differences, copy one into the other.

Except for performance problems, I don't see why you would copy only the fields that are differents (because if you copy the fields that are the same, well there won't be any difference). If you have to copy only the field that are different, I guess you'll have to make your own tool.

Upvotes: 1

Brian
Brian

Reputation: 13571

Use reflect to find all the of results of getters and setters in company and newCompany.

Basically, what I am doing here are as the following:

1. Put all the results of getters in newCompany into a HashMap called hm.

2. Scan through the results of getters in company. If hm doesn't contain any one of the results of getters in company, then the two companies are considered different.

3. If the two companies are different, set the values in company as the values in newCompany.

public static void compareAndApplyDifferences(Object o1, Object o2) {
    if(!o1.getClass().equals(o2.getClass())) {
        return;
    }
    // check if the result of getters in o1 and o2 are different
    boolean isDiff = false;
    Class<? extends Object> c1 = o1.getClass();
    Class<? extends Object> c2 = o2.getClass();
    Method[] methods1 = c1.getMethods();
    Method[] methods2 = c2.getMethods();
    Map<String, Object> hm = new HashMap<String, Object>();
    for (Method method2 : methods2) {
        if (isGetter(method2)) {
            try {
                Object getterResult = method2.invoke(o2);
                hm.put(method2.getName().substring(3), getterResult);
            } catch (IllegalAccessException e) {
            } catch (IllegalArgumentException e) {
            } catch (InvocationTargetException e) {
            }
        }
    }
    for (Method method1 : methods1) {
        if (isGetter(method1)) {
            try {
                String getterResult = (String) method1.invoke(o1);
                if (!hm.containsValue(getterResult)) {
                    isDiff = true;
                    break;
                }
            } catch (IllegalAccessException e) {
            } catch (IllegalArgumentException e) {
            } catch (InvocationTargetException e) {
            }
        }
    }

    if (isDiff) {
        // set the values in o1 as the values in o2
        for (Method method1 : methods1) {
            if (isSetter(method1)) {
                try {
                    method1.invoke(o1, hm.get(method1.getName().substring(3)));
                } catch (IllegalAccessException e) {
                } catch (IllegalArgumentException e) {
                } catch (InvocationTargetException e) {
                }
            }
        }
    } else {
        return;
    }
}

private static boolean isGetter(Method method) {
    if (!method.getName().startsWith("get"))
        return false;
    if (method.getParameterTypes().length != 0)
        return false;
    if (void.class.equals(method.getReturnType()))
        return false;
    return true;
}

private static boolean isSetter(Method method) {
    if (!method.getName().startsWith("set"))
        return false;
    if (method.getParameterTypes().length != 1)
        return false;
    return true;
}

Here's the demonstration of my program:

public static void main(String[] args) {

    Company company = new Company();
    company.setId("id12345678");
    company.setName("company Old Name");
    company.setUrl("company Old Url");

    Company newCompany = new Company();
    newCompany.setId("id12345678");
    newCompany.setName("company New Name");
    newCompany.setUrl("company New Url");

    AwesomeLibraryUtils.compareAndApplyDifferences(company, newCompany);

    System.out.println(company.getId());   // id12345678
    System.out.println(company.getName()); // company New Name
    System.out.println(company.getUrl());  // company New Url
}

Upvotes: 2

Amila
Amila

Reputation: 5213

You should override equals() method. After that you will be able to check the condition company.equals(newCompany)

Famous IDEs support auto-generation of equals method. For example, IDEA generates it as:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;

    Company company = (Company) o;

    if (id != null ? !id.equals(company.id) : company.id != null) return false;
    if (name != null ? !name.equals(company.name) : company.name != null) return false;
    return !(url != null ? !url.equals(company.url) : company.url != null);

}

Upvotes: 0

Related Questions