Reputation: 1655
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
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).
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
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
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