我如何递归地比较两个相同但未知类型的Java对象的字段值?

时间:2014-10-30 10:54:52

标签: java xml reflection jaxb

我们正在使用JAXB将XML配置文件解析为Java对象。 XML文件是版本化的,在将版本1.0和2.0加载到对象后,我们希望递归地比较相同但未知类型的两个对象(对于所有类型的事物有许多不同的配置)和它们的字段值并打印出差异

对象可能如下所示。

@XmlRootElement(name = "HelloWorld")
public class HelloWorldConfiguration {
    private List<HelloWorldObject> helloWorldObjects = new ArrayList<HelloWorldObject>();

    public HelloWorldConfiguration() {
        HelloWorldObject o = new HelloWorldObject();
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
        helloWorldObjects.add(o);
    }

    @XmlElement(name = "helloWorldObject")
    public List<HelloWorldObject> getHelloWorldObjects() {
        return helloWorldObjects;
    }

    public void setHelloWorldObjects(List<HelloWorldObject> helloWorldObjects) {
        this.helloWorldObjects = helloWorldObjects;
    }
}

public class HelloWorldObject {
    private Stage firstName = new Stage("Tony");
    private Stage secondName = new Stage("Stark");

    public Stage getFirstName() {
        return firstName;
    }

    public void setFirstName(Stage firstName) {
        this.firstName = firstName;
    }

    public Stage getSecondName() {
        return secondName;
    }

    public void setSecondName(Stage secondName) {
        this.secondName = secondName;
    }

}

例如,我们希望了解有关上述HelloWorldConfiguration对象的以下更改?

  • 还有其他&#34; HelloWorldObject&#34;列表中的项目(必须在屏幕上打印包含其attibuutes的项目)
  • &#34; HelloWorldObject&#34;在位置n有一个新的&#34; firstName&#34; value(要更改的字段或XML元素的名称及其值应打印)
  • 新的&#34; HelloWorldObject&#34;列表缩短了2个以下元素(缺少的元素必须打印所有属性和值)

我的问题如下。

  • 您是通过反映Java对象级别还是比较两个不同的XML文件来解决这个问题?
  • 那里有没有那些已经为我做过这样的事情的图书馆?在XML或Java对象级别?
  • 任何例子?

1 个答案:

答案 0 :(得分:1)

免责声明。我是JAXB2 Basics插件包的作者,其中包含JAXB2 Equals plugin


如果从XML Schema生成类,则在此用例中JAXB2 Equals plugin可能对您有用。

JAXB2 Equals plugin能够生成equals方法,这些方法执行JAXB类实例的深层结构遍历值比较:

public boolean equals(Object object) {
    final EqualsStrategy strategy = JAXBEqualsStrategy.INSTANCE;
    return equals(null, null, object, strategy);
}

public boolean equals(ObjectLocator thisLocator, ObjectLocator thatLocator, Object object, EqualsStrategy strategy) {
    if (!(object instanceof PurchaseOrderType)) {
        return false;
    }
    if (this == object) {
        return true;
    }
    final PurchaseOrderType that = ((PurchaseOrderType) object);
    {
        USAddress lhsShipTo;
        lhsShipTo = this.getShipTo();
        USAddress rhsShipTo;
        rhsShipTo = that.getShipTo();
        if (!strategy.equals(LocatorUtils.property(thisLocator, "shipTo", lhsShipTo), LocatorUtils.property(thatLocator, "shipTo", rhsShipTo), lhsShipTo, rhsShipTo)) {
            return false;
        }
    }
    {
        USAddress lhsBillTo;
        lhsBillTo = this.getBillTo();
        USAddress rhsBillTo;
        rhsBillTo = that.getBillTo();
        if (!strategy.equals(LocatorUtils.property(thisLocator, "billTo", lhsBillTo), LocatorUtils.property(thatLocator, "billTo", rhsBillTo), lhsBillTo, rhsBillTo)) {
            return false;
        }
    }
    // ...
    return true;
}

我希望你有这个想法。您可以提供一个“定位器”,用于跟踪被比较事物的位置,以及一个用于比较各个值的策略。

结果你可以:

  • 对模式派生的JAXB类实例进行深入比较。
  • 了解 的不同之处(确切的值)。
  • 了解 的区别(对象结构中的确切位置)。

整个事情都是无反射的,因此非常快。

以下是another project的摘录。这是我在比较“之前”和“之后”对象的测试之一,并记录差异。

    final EqualsStrategy strategy = new org.jvnet.hyperjaxb3.lang.builder.ExtendedJAXBEqualsStrategy() {

        @Override
        public boolean equals(ObjectLocator leftLocator,
                ObjectLocator rightLocator, Object lhs, Object rhs) {
            if (!super.equals(leftLocator, rightLocator, lhs, rhs)) {
                logger.debug("Objects are not equal.");
                super.equals(leftLocator, rightLocator, lhs, rhs);
                logger.debug("Left: "
                        + (lhs == null ? "null" : lhs.toString()));
                if (leftLocator != null) {
                    logger.debug("At [" + leftLocator.getPathAsString()
                            + "].");
                }
                logger.debug("Right: "
                        + (rhs == null ? "null" : rhs.toString()));
                if (rightLocator != null) {
                    logger.debug("At [" + rightLocator.getPathAsString()
                            + "].");
                }
                return false;
            } else

            {
                return true;
            }
        }

    };

另一方面,这种方法并不是真正的“差异”,因为您可能从VCS中了解它。它只说某些东西不同,但不计算任何“最短编辑距离”。