Подтвердить что ты не робот

Есть ли библиотека Java, которая может "отличать" два объекта?

Есть ли библиотека служебных программ Java, аналогичная программному diff Unix, но для объектов? Я ищу что-то, что может сравнить два объекта одного типа и создать структуру данных, которая представляет различия между ними (и может рекурсивно сравнивать различия в переменных экземпляра). Я не ищет Java-реализацию текстового diff. Я также не ищет помощь в том, как использовать отражение для этого.

Приложение, которое я поддерживаю, имеет хрупкую реализацию этой функциональности, которая имела некоторые плохие варианты дизайна и которая должна быть переписана, но было бы еще лучше, если бы мы могли что-то использовать с полки.

Вот пример того, что я ищу:

SomeClass a = new SomeClass();
SomeClass b = new SomeClass();

a.setProp1("A");
a.setProp2("X");

b.setProp1("B");
b.setProp2("X");

DiffDataStructure diff = OffTheShelfUtility.diff(a, b);  // magical recursive comparison happens here

После сравнения утилита сообщит мне, что "prop1" отличается между двумя объектами, а "prop2" - то же самое. Я считаю, что для DiffDataStructure наиболее естественно быть деревом, но я не собираюсь быть придирчивым, если код надежный.

4b9b3361

Ответ 1

Может быть, немного поздно, но я был в той же ситуации, что и вы, и в итоге создал свою собственную библиотеку именно для вашего прецедента. Поскольку я был вынужден сам решить проблему, я решил выпустить ее на Github, чтобы избавить других от тяжелой работы. Вы можете найти его здесь: https://github.com/SQiShER/java-object-diff

--- Изменить ---

Вот небольшой пример использования, основанный на коде OPs:

SomeClass a = new SomeClass();
SomeClass b = new SomeClass();

a.setProp1("A");
a.setProp2("X");

b.setProp1("B");
b.setProp2("X");

DiffNode diff = ObjectDifferBuilder.buildDefault().compare(a, b);

assert diff.hasChanges();
assert diff.childCount() == 1;
assert diff.getChild('prop1').getState() == DiffNode.State.CHANGED;

Ответ 2

http://javers.org - это библиотека, которая делает то, что вам нужно: имеет методы, подобные сравнению (Object leftGraph, Object rightGraph), возвращающий объект Diff. Diff содержит список изменений (ReferenceChange, ValueChange, PropertyChange), например.

given:
DummyUser user =  dummyUser("id").withSex(FEMALE).build();
DummyUser user2 = dummyUser("id").withSex(MALE).build();
Javers javers = JaversTestBuilder.newInstance()

when:
Diff diff = javers.compare(user, user2)

then:
diff.changes.size() == 1
ValueChange change = diff.changes[0]
change.leftValue == FEMALE
change.rightValue == MALE

Он может обрабатывать циклы в графах.

Кроме того, вы можете получить снимок любого объекта графика. У Javers есть сериализаторы JSON и десериализаторы для моментального снимка и изменения, поэтому вы можете легко их сохранить в базе данных. С помощью этой библиотеки вы можете легко реализовать модуль для аудита.

Ответ 3

Да, библиотека java-util имеет класс GraphComparator, который будет сравнивать два графических объекта Java. Он возвращает разницу в виде списка дельт. GraphComparator также позволяет вам объединять и применять дельта. Этот код имеет только зависимости от JDK, других библиотек.

Ответ 4

У всех библиотек Javers есть поддержка только Java 7, я был в ситуации, так как я хочу, чтобы это было использовано для проекта Java 6, поэтому мне пришлось взять исходный код и изменить его способ работы на Java 6 ниже код github.

https://github.com/sand3sh/javers-forJava6

Jar link: https://github.com/sand3sh/javers-forJava6/blob/master/build/javers-forjava6.jar

Я только изменил поддерживаемые Java 7 '< > ' встроенные преобразования конверсий в поддержку Java 6 Я не гарантирую, что все функции будут работать, так как я прокомментировал несколько ненужных кодов для меня, он работает для сравнения всех пользовательских объектов.

Ответ 5

Возможно, это поможет, в зависимости от того, где вы используете этот код, это может быть полезно или проблематично. Протестировал этот код.

    /**
 * @param firstInstance
 * @param secondInstance
 */
protected static void findMatchingValues(SomeClass firstInstance,
        SomeClass secondInstance) {
    try {
        Class firstClass = firstInstance.getClass();
        Method[] firstClassMethodsArr = firstClass.getMethods();

        Class secondClass = firstInstance.getClass();
        Method[] secondClassMethodsArr = secondClass.getMethods();


        for (int i = 0; i < firstClassMethodsArr.length; i++) {
            Method firstClassMethod = firstClassMethodsArr[i];
            // target getter methods.
            if(firstClassMethod.getName().startsWith("get") 
                    && ((firstClassMethod.getParameterTypes()).length == 0)
                    && (!(firstClassMethod.getName().equals("getClass")))
            ){

                Object firstValue;
                    firstValue = firstClassMethod.invoke(firstInstance, null);

                logger.info(" Value "+firstValue+" Method "+firstClassMethod.getName());

                for (int j = 0; j < secondClassMethodsArr.length; j++) {
                    Method secondClassMethod = secondClassMethodsArr[j];
                    if(secondClassMethod.getName().equals(firstClassMethod.getName())){
                        Object secondValue = secondClassMethod.invoke(secondInstance, null);
                        if(firstValue.equals(secondValue)){
                            logger.info(" Values do match! ");
                        }
                    }
                }
            }
        }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
}

Ответ 6

Более простой подход, чтобы быстро рассказать вам, являются ли два объекта разными, заключается в использовании библиотеки apache commons

    BeanComparator lastNameComparator = new BeanComparator("lname");
    logger.info(" Match "+bc.compare(firstInstance, secondInstance));