2012-03-09 90 views
12

我想通过比较生成的对象与原始对象来验证序列化和反序列化例程。例程可以序列化任意深度嵌套的类,因此我想要一个比较例程,它可以给出原始和最终实例,并反射地遍历每个值类型并比较值并迭代地跳入引用类型以比较值。深度反射比较等于

我已经试过了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); 
} 
+0

如果反射等于只是比较引用,那么它有一个错误。它应该做的比这更多。 – DwB 2012-03-09 11:04:17

+0

@DwB我怀疑代码的意图是允许您在特定的类中反射性地实现equals()。这与我想要反映的两个对象实例不同。在这种情况下,它不是一个错误,而是一种失望! – 2012-03-09 11:11:30

+0

我失去了半天,EqualsBuilder这种弱无证行为。如果传递对象的字段是非基元,则builde rjust调用object.equals()。非常令人失望和无用。 – AlexWien 2014-03-03 17:36:40

回答

12

从这个问题的答案https://stackoverflow.com/a/1449051/116509和一些初步的测试,它看起来像Unitils' ReflectionAssert.assertReflectionEquals做你期待什么。 (编辑:但可能会被放弃,所以你可以尝试AssertJ https://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html#field-by-field-recursive

我非常担心EqualsBuilder的这种行为,所以谢谢你的问题。在这个网站上有不少答案推荐它 - 我想知道推荐它的人是否意识到它是这样做的?

+0

我分享你的惊喜,尽管对EqualsBuilder公平,而且正如我对这个问题所评论的那样,我认为这是对例程意图的误解。也许这是可以做得更清楚的事情。 – 2012-03-09 11:28:01

+2

javadoc应该修改恕我直言,使其更清晰。 – artbristol 2012-03-09 11:29:56

+0

我已经做了一些关于assertReflectionEquals的初始测试,它似乎工作。非常感谢 – 2012-03-09 15:18:33

0

在有问题的类上实现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; 
    } 
} 
+2

我明白这是实现这一目标的正常方式,对于大多数情况是推荐的方式。用于计算相等性的内置机制是健壮且可扩展的,以允许自定义类定义相同的含义。不幸的是,我的要求阻止我能够在所有嵌套类上实现equals(),因此我希望能够使用反射。谢谢 – 2012-03-09 11:15:49

+0

这种方法的问题是它无法处理循环对象图。使用这种方法比较循环对象图将导致无限递归。 – jhegedus 2014-02-12 08:50:26

+0

我同意循环对象图将是一个问题。因为它们是序列化和故障转移(这可能只是序列化的症状)。 – DwB 2014-02-12 13:49:59

3

一种方法是使用反射比较对象 - 但这很棘手。另一种策略是比较序列化对象的字节数组:

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

} 

您的应用程序序列化,因此这种做法似乎是你的问题最快的解决方法(在CPU操作方面)进行反序列化对象。

+0

干杯约翰尼,我曾想过比较序列化的形式,这是一个简洁的方法,它解决了EqualsBuilder的缺点。这表示它不会完全验证序列化和反序列化,因为它不能完全确认原始的非序列化形式与反序列化形式相同。问候 – 2012-03-09 11:31:38

+0

嘿霍华德,你可以举一个例子,当这种情况可能发生?我确信一个对象只有一个序列化表单和字节表示。 – whysoserious 2012-03-09 11:45:13

+0

嗨,约翰尼,请记住,这是为了测试我的越野车代码。如果我的序列化程序无法序列化一个特定的字段,那么比较序列化的版本将不会检测到问题。 – 2012-03-09 14:16:34