简体   繁体   中英

How would I compare field values of two Java objects of the same but unknown type recursively?

We are parsing XML configuration files with JAXB into Java objects. The XML files are versioned and after loading version 1.0 and 2.0 into objects we would like to compare the two objects of the same but unknown type (there are many different configurations for all kinds of things) recursively and their field values and print out the differences.

An object might look as follows.

@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;
    }

}

For example we would like to be informed about following changes about the above HelloWorldConfiguration object?

  • there is additional "HelloWorldObject" item in the list (the item with its attributes must be printed on screen)
  • the "HelloWorldObject" at the position n has a new "firstName" value (the name of the field or XML element that changed and its value should be printed)
  • the new "HelloWorldObject" list is shorter by 2 following elements (the missing elements must be printed with all attributes and values)

My questions are as follows.

  • Would you solve this with reflection on the Java object level or compare the two different XML files?
  • Are there any libraries out there that already do something like that for me? On XML or Java object level?
  • Any examples?

Disclaimer. I am the author of the JAXB2 Basics plugin package which includes the JAXB2 Equals plugin .


If you generate your classes from an XML Schema, the JAXB2 Equals plugin might be of use for you in this use case.

The JAXB2 Equals plugin is capable of generating equals methods which do deep structure-traversing value comparison of JAXB class instances:

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

I hope you've got the idea. You can provide a "locator" which would track the location of things being compared and a strategy which will do the comparison of individual values.

As the result you can:

  • Do an in-depth comparison of schema-derived JAXB class instances.
  • Know what is different (exact values).
  • Know where are the differences (exact location in the object structure).

And the whole thing is reflection-free and therefore quite fast.

Below is a snippet from another project . This is from one of the tests where I compare object "before" and "after" and log the differences.

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

    };

From the other hand, this approach is not a real "diff" as you may know it from VCS. It only says that something is different, but does not calculate any "shortest edit distance".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM