找出两个用于版本跟踪的java bean之间的差异

说我有一个java bean /一个有100个字段的实体(在这种情况下inheritance或不相关)。 更新操作后 – 在事务中,我想确定修改哪些字段以跟踪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, InvocationTargetException, NoSuchMethodException { SampleBean oldSample = new SampleBean("John", "Doe", 1971); SampleBean newSample = new SampleBean("John X.", "Doe", 1971); SampleBean diffSample = (SampleBean) compareObjects(oldSample, newSample, new HashSet<>(Arrays.asList("lastName")), 10L); } public Object compareObjects(Object oldObject, Object newObject, Set propertyNamesToAvoid, Long deep) { return compareObjects(oldObject, newObject, propertyNamesToAvoid, deep, null); } private Object compareObjects(Object oldObject, Object newObject, Set propertyNamesToAvoid, 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, propertyNamesToAvoid, deep != null ? deep - 1 : null, propertyPath + "."); propUtils.setProperty(diffObject, propertyName, diffProperty); } else { if (!Objects.deepEquals(property1, property2)) { propUtils.setProperty(diffObject, propertyName, 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,它正是你所需要的 – 对象审计和差异框架。 使用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 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, author:author, 2015-01-07 23:00:10 new object: 'org.javers.demo.User/1 

您可以使用reflection来加载字段,然后在每个对象上调用它们并比较结果。

示例源代码可能如下所示:

 public static  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签出属性。