Глубоко рефлексивное сравнение равно - PullRequest
13 голосов
/ 09 марта 2012

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

Я пробовал Apache Commons Lang EqualsBuilder.reflectionEquals(inst1, inst2), но это не слишком глубокое сравнение, оно просто сравнивает ссылочные типы на равенство, а не углубляется в них:

Следующий код иллюстрирует мою проблему. Первый вызов reflectionEquals возвращает true, а второй возвращает false.

Может ли кто-нибудь порекомендовать библиотечную процедуру?

class dummy {
    dummy2 nestedClass;
}

class dummy2 {
    int intVal;
}

@Test
public void testRefEqu() {

    dummy inst1 = new dummy();
    inst1.nestedClass = new dummy2();
    inst1.nestedClass.intVal = 2;
    dummy inst2 = new dummy();
    inst2.nestedClass = new dummy2();
    inst2.nestedClass.intVal = 2;
    boolean isEqual = EqualsBuilder.reflectionEquals(inst1.nestedClass, inst2.nestedClass);
    isEqual = EqualsBuilder.reflectionEquals(inst1, inst2);
}

Ответы [ 4 ]

13 голосов
/ 09 марта 2012

Из ответа на этот вопрос https://stackoverflow.com/a/1449051/116509 и некоторых предварительных тестов видно, что ReflectionAssert.assertReflectionEquals от Unitils делает то, что вы ожидаете.(Изменить: но можно отказаться, поэтому вы можете попробовать AssertJ https://joel -costigliola.github.io / assertj / assertj-core-features-highlight.html # field-by-field-recursive )

Я очень встревожен этим поведением EqualsBuilder, так что спасибо за вопрос.На этом сайте есть довольно много ответов, которые рекомендуют это - интересно, люди, рекомендующие это, поняли, что это делает?

4 голосов
/ 09 марта 2012

Один из методов - сравнение объектов с использованием отражения, но это сложно. Другой стратегией будет сравнение массивов байтов сериализованных объектов:

class dummy implements Serializable {
    dummy2 nestedClass;
}

class dummy2  implements Serializable {
    int intVal;
}

@Test
public void testRefEqu() throws IOException {

    dummy inst1 = new dummy();
    inst1.nestedClass = new dummy2();
    inst1.nestedClass.intVal = 2;

    dummy inst2 = new dummy();
    inst2.nestedClass = new dummy2();
    inst2.nestedClass.intVal = 2;

    boolean isEqual1 = EqualsBuilder.reflectionEquals(inst1.nestedClass, inst2.nestedClass);
    boolean isEqual2 = EqualsBuilder.reflectionEquals(inst1, inst2);

    System.out.println(isEqual1);
    System.out. println(isEqual2);

    ByteArrayOutputStream baos1 =new ByteArrayOutputStream();
    ObjectOutputStream oos1 = new ObjectOutputStream(baos1);
    oos1.writeObject(inst1);
    oos1.close();

    ByteArrayOutputStream baos2 =new ByteArrayOutputStream();
    ObjectOutputStream oos2 = new ObjectOutputStream(baos2);
    oos2.writeObject(inst1);
    oos2.close();

    byte[] arr1 = baos1.toByteArray();
    byte[] arr2 = baos2.toByteArray();

    boolean isEqual3 = Arrays.equals(arr1, arr2);

    System.out.println(isEqual3);

}

Ваше приложение сериализует и десериализует объекты, поэтому этот подход, по-видимому, является самым быстрым решением (с точки зрения операций ЦП) для вашей проблемы.

0 голосов
/ 24 апреля 2019

Вы можете использовать поле AssertJ для рекурсивного сравнения полей , например:

import static org.assertj.core.api.BDDAssertions.then;

then(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
0 голосов
/ 09 марта 2012

Реализуйте метод equals() в рассматриваемых классах.Эквивалент каждого вызова сравнивает равенство вложенных классов (или, если хотите, сравнивает равенство членов данных).Правильно написанный метод equals всегда приведет к глубокому сравнению.

В вашем примере класс dummy equals будет выглядеть примерно так:

public boolean equals(Object other)
{
    if (other == this) return true;
    if (other instanceOf dummy)
    {
        dummy dummyOther = (dummy)other;
        if (nestedClass == dummyOther.nestedClass)
        {
           return true;
        }
        else if (nestedClass != null)
        {
           return nestedClass.equals(dummyOther);
        }
        else // nestedClass == null and dummyOther.nestedClass != null.
        {
           return false;
        }
    }
    else
    {
      return false;
    }
}
...