find out the differences between two java beans for version tracking

后端 未结 4 1013
耶瑟儿~
耶瑟儿~ 2020-11-30 06:13

say i have a java bean/an entity with 100 fields (inherited or not it is not relevant in this case). After update operations - in a transaction, i want to determine which fi

相关标签:
4条回答
  • 2020-11-30 06:18

    You can use Apache BeanUtils to checkout the properties.

    0 讨论(0)
  • 2020-11-30 06:19

    Hey look at Javers it's exactly what you need - objects auditing and diff framework . With Javers you can persist changes done on your domain objects with a single javers.commit() call after every update. When you persist some changes you can easily read them by javers.getChangeHistory, e.g.

    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()));
    }
    

    and the output is:

    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
    
    0 讨论(0)
  • 2020-11-30 06:42

    You could use Apache Commons Beanutils. Here's a simple example:

    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<String> propertyNamesToAvoid, Long deep) {
        return compareObjects(oldObject, newObject, propertyNamesToAvoid, deep, null);
    }
    
    private Object compareObjects(Object oldObject, Object newObject, Set<String> 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;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 06:42

    You can use reflection to load the fields and then invoke them on each object and compare the result.

    Example source code might look like this:

    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
    
                }
    
            }
    

    FYI, this code will work only on public fields declared for class.

    0 讨论(0)
提交回复
热议问题