问题描述
|
说我有一个Java bean /有100个字段的实体(是否继承,在这种情况下不相关)。更新操作后-在事务中,我想确定修改哪些字段以跟踪CVS之类的更新。最简单的方法是什么?有任何框架建议吗?我是否应该制作此对象的两个实例并遍历所有字段并匹配字段的值?在这种情况下最佳平等方法会如何出现?以下equals()似乎很尴尬:
return (field1.equals(o.field1)) &&
(field2.equals(o.field2)) &&
(field3.equals(o.field3)) &&
...
(field100.equals(o.field100));
解决方法
您可以使用Apache Commons Beanutils。这是一个简单的示例:
package at.percom.temp.zztests;
import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.beanutils.PropertyUtilsBean;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
public class Main {
public static void main(String[] args) throws IllegalAccessException,InvocationTargetException,NoSuchMethodException {
Main main = new Main();
main.start();
}
public void start() throws IllegalAccessException,NoSuchMethodException {
SampleBean oldSample = new SampleBean(\"John\",\"Doe\",1971);
SampleBean newSample = new SampleBean(\"John X.\",1971);
SampleBean diffSample = (SampleBean) compareObjects(oldSample,newSample,new HashSet<>(Arrays.asList(\"lastName\")),10L);
}
public Object compareObjects(Object oldObject,Object newObject,Set<String> propertyNamesToAvoid,Long deep) {
return compareObjects(oldObject,newObject,propertyNamesToAvoid,deep,null);
}
private Object compareObjects(Object oldObject,Long deep,String parentPropertyPath) {
propertyNamesToAvoid = propertyNamesToAvoid != null ? propertyNamesToAvoid : new HashSet<>();
parentPropertyPath = parentPropertyPath != null ? parentPropertyPath : \"\";
Object diffObject = null;
try {
diffObject = oldObject.getClass().newInstance();
} catch (Exception e) {
return diffObject;
}
BeanMap map = new BeanMap(oldObject);
PropertyUtilsBean propUtils = new PropertyUtilsBean();
for (Object propNameObject : map.keySet()) {
String propertyName = (String) propNameObject;
String propertyPath = parentPropertyPath + propertyName;
if (!propUtils.isWriteable(diffObject,propertyName) || !propUtils.isReadable(newObject,propertyName)
|| propertyNamesToAvoid.contains(propertyPath)) {
continue;
}
Object property1 = null;
try {
property1 = propUtils.getProperty(oldObject,propertyName);
} catch (Exception e) {
}
Object property2 = null;
try {
property2 = propUtils.getProperty(newObject,propertyName);
} catch (Exception e) {
}
try {
if (property1 != null && property2 != null && property1.getClass().getName().startsWith(\"com.racing.company\")
&& (deep == null || deep > 0)) {
Object diffProperty = compareObjects(property1,property2,deep != null ? deep - 1 : null,propertyPath + \".\");
propUtils.setProperty(diffObject,propertyName,diffProperty);
} else {
if (!Objects.deepEquals(property1,property2)) {
propUtils.setProperty(diffObject,property2);
System.out.println(\"> \" + propertyPath + \" is different (oldValue=\\\"\" + property1 + \"\\\",newValue=\\\"\"
+ property2 + \"\\\")\");
} else {
System.out.println(\" \" + propertyPath + \" is equal\");
}
}
} catch (Exception e) {
}
}
return diffObject;
}
public class SampleBean {
public String firstName;
public String lastName;
public int yearOfBirth;
public SampleBean(String firstName,String lastName,int yearOfBirth) {
this.firstName = firstName;
this.lastName = lastName;
this.yearOfBirth = yearOfBirth;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getYearOfBirth() {
return yearOfBirth;
}
}
}
,嘿,看看Javers正是您所需要的-对象审核和diff框架。使用Javers,您可以在每次更新后通过一次javers.commit()
调用来保留对域对象所做的更改。当您坚持进行某些更改时,可以按javers.getChangeHistory
轻松读取它们,例如
public static void main(String... args) {
//get Javers instance
Javers javers = JaversBuilder.javers().build();
//create java bean
User user = new User(1,\"John\");
//commit current state
javers.commit(\"author\",user);
//update operation
user.setUserName(\"David\");
//commit change
javers.commit(\"author\",user);
//read 100 last changes
List<Change> changes = javers.getChangeHistory(instanceId(1,User.class),100);
//print change log
System.out.printf(javers.processChangeList(changes,new SimpleTextChangeLog()));
}
输出为:
commit 2.0,author:author,2015-01-07 23:00:10
changed object: org.javers.demo.User/1
value changed on \'userName\' property: \'John\' -> \'David\'
commit 1.0,2015-01-07 23:00:10
new object: \'org.javers.demo.User/1
,您可以使用反射来加载字段,然后在每个对象上调用它们并比较结果。
示例源代码可能如下所示:
public static <T> void Compare(T source,T target) throws IllegalArgumentException,IllegalAccessException {
if(source == null) {
throw new IllegalArgumentException(\"Null argument not excepted at this point\");
}
Field[] fields = source.getClass().getFields();
Object sourceObject;
Object targetObject;
for(Field field : fields){
sourceObject = field.get(source);
targetObject = field.get(target);
//Compare the object
}
}
仅供参考,此代码仅适用于为类声明的公共字段。
,您可以使用Apache BeanUtils检出属性。