Общий алгоритм генерации различий полей в двух бинов? - PullRequest
9 голосов
/ 23 февраля 2009

Допустим, у вас есть два экземпляра одного и того же типа bean-компонента, и вы хотите отобразить сводку того, что изменилось между двумя экземплярами - например, у вас есть bean-компонент, представляющий пользовательские настройки в вашем приложении, и вы Хотелось бы иметь возможность отображать список того, что изменилось в новых настройках, которые отправляет пользователь (экземпляр № 1), по сравнению с тем, что уже сохранено для пользователя (экземпляр № 2).

Существует ли обычно используемый алгоритм или шаблон проектирования для такой задачи, как эта, возможно, что-то, что можно абстрагировать и повторно использовать для различных типов bean-компонентов? (Мне трудно придумать подходящее название для проблемы такого типа, чтобы знать, на что Google). Я проверил обыкновенные beanutils и ничего не выскочил на меня.

Ответы [ 6 ]

6 голосов
/ 23 февраля 2009

Если вы говорите о сравнении значений, я бы подумал об использовании отражения и просто сравнивать их поле за полем.

Примерно так:


    Field[] oldFields = oldInstance.class.getDeclaredFields();
    Field[] newFields = newInstance.class.getDeclaredFields();
    StringBuilder changes = new StringBuilder();

    Arrays.sort(oldFields);
    Arrays.sort(newFields);

    int i = 0;
    for(Field f : oldFields)
    {
       if(!f.equals(newFields[i]))
       {
          changes.append(f.getName()).append(" has changed.\n");
       }
       i++;
    }

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

3 голосов
/ 15 июня 2012

Эти библиотеки должны помочь.

https://code.google.com/p/beandiff/ - основанная на аннотациях библиотека сравнения компонентов. Лицензия Apache 2.0

https://github.com/SQiShER/java-object-diff/ - Бин отличается в зависимости от модели посетителя. Лицензия Apache 2.0

У нас было требование генерировать разницу между bean-компонентами в формате json для целей аудита. В итоге мы реализовали его с использованием библиотеки beandiff .

** РЕДАКТИРОВАТЬ ** Это выглядит как новый вариант. Я не использовал это все же.

http://beandiff.org/

Надеюсь, это поможет.

3 голосов
/ 23 февраля 2009

Мы сделали что-то похожее с bean utils, и это сработало хорошо. На что следует обратить внимание: Вы углубляетесь в полевые объекты - если Person содержит Address и адрес меняется, вы говорите, что адрес изменился или этот address.postalCode изменился (мы делаем)? Вы возвращаете список свойств, старое значение, новое значение из diff (мы делаем)? Как вы хотите обрабатывать даты - если все, что вас волнует, это часть даты, то ваше сравнение должно игнорировать время? Как сказать, какие поля игнорировать?

Это на самом деле не ответ с копированием и вставкой, а скорее список вещей, которые не были сразу очевидны, когда мы написали наши различия.

Что касается реализации, у нас просто есть статический метод util, который берет два bean-компонента и список свойств для сравнения, а затем возвращает карту свойств в Pair, содержащую старое значение и новое значение. Затем у каждого компонента есть метод diff(Object o), который вызывает статический метод util по мере необходимости.

2 голосов
/ 23 февраля 2009

Отражение не поддерживает порядок поля при следующем вызове: более безопасен порядок массивов.

/*
*declarations of variables
*/

Arrays.sort(oldFields);//natural order - choice 1
Arrays.sort(newFields, new Ordinator());//custom Comparator - choice 2

/*
*logic of comparations between elements
*/

В варианте 2 вы можете решить логику сортировки (КАК Сортировать элементы) с помощью внутреннего класса Ordinator , расширяющего Comparator .

PS код - это черновик

1 голос
/ 23 февраля 2009

Хорошие ответы выше.

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

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

Если существует условный тест, который делает блок полей релевантным или нет, вы сериализуете / десериализуете значение «истина или ложь» условного теста и используете его, чтобы решить, стоит ли сериализовать и / или десериализовать затронутые поля. И это хорошо повторяется.

Просто предложение.

0 голосов
/ 08 марта 2013

Решение с использованием отражения и стандартных структур данных.

    Field[] declaredFields = ClassOne.class.getDeclaredFields();
    Field[] declaredFields2 = ClassTwo.class.getDeclaredFields();
    ArrayList<String> one = new ArrayList<String>();
    ArrayList<String> two = new ArrayList<String>();
    for (Field field : declaredFields)
    {
        one.add(field.getName());
    }

    for (Field field : declaredFields2)
    {
        two.add(field.getName());
    }

    List<String> preone = (List<String>)one.clone();

    one.removeAll(two);
    two.removeAll(preone);
    Collections.sort(one);
    Collections.sort(two);

    System.out.println("fields only in One : " + one);
    System.out.println("fields only in Two : " + two);
...