如何递归地比较相同但未知类型的两个Java对象的字段值?
我们正在使用JAXB将XML配置文件解析为Java对象。XML文件是版本化的,在将版本1.0和2.0加载到对象中之后,我们希望递归地比较相同但未知类型的两个对象(对于所有类型的对象有许多不同的配置)及其字段值,并打印出差异如何递归地比较相同但未知类型的两个Java对象的字段值?,java,xml,reflection,jaxb,Java,Xml,Reflection,Jaxb,我们正在使用JAXB将XML配置文件解析为Java对象。XML文件是版本化的,在将版本1.0和2.0加载到对象中之后,我们希望递归地比较相同但未知类型的两个对象(对于所有类型的对象有许多不同的配置)及其字段值,并打印出差异 final EqualsStrategy strategy = new org.jvnet.hyperjaxb3.lang.builder.ExtendedJAXBEqualsStrategy() { @Override public
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;
}
}
};
对象可能如下所示
@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;
}
}
@XmlRootElement(name=“HelloWorld”)
公共类HelloWorldConfiguration{
私有列表helloWorldObjects=new ArrayList();
公共HelloWorldConfiguration(){
HelloWorldObject o=新的HelloWorldObject();
helloWorldObjects.add(o);
helloWorldObjects.add(o);
helloWorldObjects.add(o);
helloWorldObjects.add(o);
helloWorldObjects.add(o);
}
@XmlElement(name=“helloWorldObject”)
公共列表getHelloWorldObjects(){
返回helloWorldObjects;
}
public void setHelloWorldObjects(列出helloWorldObjects){
this.helloWorldObjects=helloWorldObjects;
}
}
公共类HelloWorldObject{
私人舞台名=新舞台(“托尼”);
私人舞台secondName=新舞台(“斯塔克”);
公共阶段getFirstName(){
返回名字;
}
public void setFirstName(Stage firstName){
this.firstName=firstName;
}
公共阶段getSecondName(){
返回secondName;
}
public void setSecondName(Stage secondName){
this.secondName=secondName;
}
}
例如,我们希望了解有关上述HelloWorldConfiguration对象的以下更改
- 列表中还有其他“HelloWorldObject”项(必须在屏幕上打印带有属性的项)
- 位置n处的“HelloWorldObject”有一个新的“firstName”值(已更改的字段或XML元素的名称及其值应打印出来)
- 新的“HelloWorldObject”列表缩短了以下2个元素(缺少的元素必须与所有属性和值一起打印)
@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;
}
}
- 您是在Java对象级别上通过反射来解决这个问题,还是比较两个不同的XML文件
- 有没有图书馆已经为我做了类似的事情?在XML还是Java对象级别
- 有什么例子吗
如果从XML模式生成类,则在本用例中可能会用到 能够生成对JAXB类实例进行深层结构遍历值比较的
equals
方法:
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类实例
- 了解不同之处(精确值)
- 知道差异在哪里(在对象结构中的确切位置)
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;
}
}
};
从另一方面来说,这种方法并不像你从风投那里知道的那样是一种真正的“差别”。它只是说有些东西是不同的,但没有计算任何“最短编辑距离”。谷歌搜索“xml diff java”找到了这样一个答案:实际上很少有用例需要反射。那些处理真正未知数据的。考虑使用A来确定对象具有哪些特定配置。如果对象包含其他类似的对象,您只需递归地执行此操作,直到遍历整个对象图。这种方法不需要我知道对象由哪些字段组成(字段的确切数据类型和名称)以及对象的类型吗?@TonyStark不,我不这么认为。请参阅答案中的最后一个代码段-没有提到特定的类型或字段。然而,这种方法仅限于模式派生的类。当通过JAXB2 Equals插件进行增强时,它们实现了
Equals
接口。这是一个先决条件。但在比较时,您不需要知道确切的类型、值和字段。