2017-08-09 81 views
2

我使用java-object-diff來獲取由JAXB從xml解析的兩個對象之間的差異。在下面的示例中,我使用相同的字符串來測試是否獲得任何差異,但log.info("has changes: " + diff5.hasChanges());日誌true對象不同hasChanges應該檢測到沒有更改

JAXBContext context1 = JAXBContext.newInstance(Item.class); 
Unmarshaller m1 = context1.createUnmarshaller(); 
Item base = (Item) m1.unmarshal(new StringReader(s)); 
Item working = (Item) m1.unmarshal(new StringReader(s)); 
DiffNode diff5 = ObjectDifferBuilder 
     .buildDefault() 
     .compare(working, base); 
log.info("has changes: " + diff5.hasChanges()); 
diff5.visit((node, visit) -> { 
    final Object baseValue = node.canonicalGet(base); 
    final Object workingValue = node.canonicalGet(working); 
    final String message = node.getPath() + " changed from " + 
      baseValue + " to " + workingValue; 
    System.out.println(message); 
}); 

的信息,我從得到的System.out.println始終不變,稱它已經從null改爲<the actual value>這裏面有財產。例如。

content changed from null to Mit dem Wasserinonisator 

我已經驗證了這兩種Items有兩個actualy相同的內容,沒有不null,但完全相同的內容。

Item是一個有很多子類(所有獲取者和設置者都存在)的pojo,例如,

public class Item { 

@XmlElement(name = "ASIN", required = true) 
protected String asin; 
@XmlElement(name = "ParentASIN") 
protected String parentASIN; 
@XmlElement(name = "Errors") 
protected Errors errors; 
@XmlElement(name = "DetailPageURL") 
protected String detailPageURL; 
@XmlElement(name = "ItemLinks") 
protected ItemLinks itemLinks; 
@XmlElement(name = "SalesRank") 
protected String salesRank; 
@XmlElement(name = "SmallImage") 
protected Image smallImage; 
} 

有什麼辦法讓java-object-diff工作,讓它正確比較值嗎?

+0

顯然'node.canonicalGet(base)'返回'null'。那麼'DiffNode'和'ObjectDifferBuilder'的實現是什麼? –

+0

我試圖用你的代碼重現你的問題,但我看到了不同的行爲。當我運行該程序時,diff5.hasChanges()爲false。請仔細檢查您在運行時向我們顯示源代碼。 –

+0

Ja,das ist auf jeden Fall genau der Code den ich benutze。爲了達到這個目的,你需要知道的是, @TobiasOtto – Michael

回答

1

經過仔細觀察your code我知道什麼是錯的。第一個問題是,JAXB不會生成equals方法。大多數情況下,這不是問題,因爲ObjectDiffer可以根據層次結構建立對象之間的關係。當涉及到有序或無序Collections時,情況會變得更加複雜,因爲ObjectDiffer需要某種方法來建立基礎和工作實例中的集合項之間的關係。默認情況下,它依賴於底層集合的查找機制(這通常涉及或多種方法hashCodeequalscompareTo

你的情況,這種關係不能成立,因爲沒有你的類的(但特別那些包含在ListsSets中的)實施適當的equals方法。這意味着實例只與自己相同。事實進一步複雜化,即負責任的類代表價值對象,並且沒有任何硬標識符,可用於輕鬆建立關係。因此唯一的選擇是提供簡單比較所有屬性的自定義等號方法。結果是,對這些對象稍作修改將導致ObjectDiffer將基本版本標記爲REMOVED,並將工作版本標記爲ADDED。但它們也不會將它們標記爲CHANGED,但實際上並未發生變化。所以這是一些事情。

我不知道它是多麼容易使JAXB生成自定義equals方法,所以這裏有一些可供選擇的解決方案可能與Java對象-DIFF:

  1. 實現對問題的類型你自己de.danielbechler.diff.identity.IdentityStrategy併爲他們提供到ObjectDifferBuilder,像這樣(例如使用Java 8個lambda表達式):

    ObjectDifferBuilder 
        .startBuilding() 
        .identity() 
        .ofCollectionItems(ItemLinks.class, "itemLink").via((working, base) -> { 
        ItemLink workingItemLink = (ItemLink) working; 
        ItemLink baseItemLink = (ItemLink) base; 
        return StringUtils.equals(workingItemLink.getDescription(), baseItemLink.getDescription()) 
         && StringUtils.equals(workingItemLink.getURL(), baseItemLink.getURL()); 
        }) 
        // ... 
        .and().build(); 
    
  2. 比較過程中忽略問題的性質。顯然,這可能不是你想要的,但是如果你不關心具體的對象,這是一個簡單的解決方案。

    ObjectDifferBuilder 
        .startBuilding() 
        .inclusion() 
        .exclude().type(Item.ImageSets.class) 
        .and().build(); 
    

導致JAXB生成自定義equals方法將是我去首選方式加以解決。我發現another post,聲稱它是可能的,所以也許你想先試一試,所以你不必定製你的ObjectDiffer

我希望這有助於!

+0

謝謝!所以我只是讓JAXB創建適當的equals方法(或者如果第一次失敗,我的IDE),它會工作。很好的項目btw。 ! – Michael

相關問題