2014-06-12 168 views
1

期間,我有一個對象結構如下所示:傑克遜設置值反序列化

public class Product { 
    int id; 
    String name; 
    Size[] sizes; 
    boolean organic; 
} 

public class Size { 
    int id; 
    String value; 
    @JsonIgnore String info; 
} 

在解析JSON的產品類,我想每個尺寸的信息設置爲String"Organic"。在organic屬性的setter中,我檢查值並遍歷大小,爲每個大小設置信息。

@JsonProperty("organic") 
public void setOrganic(boolean organic) { 
    this.organic = organic; 
    if (organic) 
     for(Size size : sizes) size.info = "Organic"; 
} 

首先,這種做法似乎是脆的,因爲它依賴於JSON屬性的順序上,其次,它並不總是似乎工作。對於JSON具有更多屬性的生產環境,我似乎可以在子對象(此處爲Size)上設置屬性,並在解析過程中讀取並記錄它們,但是當我從最終的反序列化對象中讀取它們時值始終爲空。同樣,這種行爲似乎與我設置測試的較小測試案例不同。

有誰知道更好的方法來做到這一點?

+0

無法初始化與「有機」的信息? –

+0

哦,對不起...錯過了條件。 –

+0

我看到.......... –

回答

1

要做到這一點的適當位置應該在這些類之外,並且這種類型的業務邏輯更合適。

您可以創建一個Builder類,它允許您爲結果對象設置所有屬性,並在調用構造最終對象的build()方法時,根據需要設置任何其他值。然後,您可以將Jackson註釋應用於Builder類,並對其應用任何驗證,而不是創建的類。這樣,您就可以保證產品的任何實例都是完整有效的。

如果您採用我的原始建議並將邏輯移入應用程序的業務層,那麼您只需將構建器傳遞給適當的方法,檢查Product.Builder上的有機值,然後遍歷Size .Builder列表並適當更改其信息值。

使用建設者,保持邏輯可能是這個樣子(你正在尋找的邏輯是在底部一路):

public class Size { 
    private final int id; 
    private final String value; 
    private final String info; 

    public Size(int id, String value, String info) { 
     this.id = id; 
     this.value = value; 
     this.info = info; 
    } 

    public int getId() { 
     return id; 
    } 

    public String getValue() { 
     return value; 
    } 

    public String getInfo() { 
     return info; 
    } 

    public static class Builder { 
     private int id; 
     private String value; 
     private String info; 

     public Builder setId(int id) { 
      this.id = id; 
      return this; 
     } 

     public Builder setValue(String value) { 
      this.value = value; 
      return this; 
     } 

     @JsonIgnore 
     public Builder setInfo(String info) { 
      this.info = info; 
      return this; 
     } 

     public Size build() { 
      return new Size(id, value, info); 
     } 
    } 
} 

public class Product { 
    private final int id; 
    private final String name; 
    private final Size[] sizes; 
    private final boolean organic; 

    public Product(int id, String name, Size[] sizes, boolean organic) { 
     this.id = id; 
     this.name = name; 
     this.sizes = sizes; 
     this.organic = organic; 
    } 

    public int getId() { 
     return id; 
    } 

    public String getName() { 
     return name; 
    } 

    public Size[] getSizes() { 
     return sizes; 
    } 

    public boolean isOrganic() { 
     return organic; 
    } 

    public static class Builder { 
     private int id; 
     private String name; 
     private List<Size.Builder> sizeBuilders; 
     private boolean organic; 

     public Builder setId(int id) { 
      this.id = id; 
      return this; 
     } 

     public Builder setName(String name) { 
      this.name = name; 
      return this; 
     } 

     public Builder setSizeBuilders(List<Size.Builder> sizeBuilders) { 
      this.sizeBuilders = sizeBuilders; 
      return this; 
     } 

     public Builder setOrganic(boolean organic) { 
      this.organic = organic; 
      return this; 
     } 

     public Product build() { 
      if (organic) { 
       for (Size.Builder sizeBuilder : sizeBuilders) { 
        sizeBuilder.setInfo("Organic"); 
       } 
      } 
      Size[] sizes = new Size[sizeBuilders.size()]; 
      for (int i = 0; i < sizeBuilders.size(); i++) { 
       sizes[i] = sizeBuilders.get(i).build(); 
      } 
      return new Product(id, name, sizes, organic); 
     } 
    } 
} 
+0

太棒了!有點不相干,但是在解析時可以在ObjectMapper上定義'Builder',這樣我就可以注入基於productFlavors的不同構建器了? –

+0

如果您知道需要預先解析的類型,那麼您可以像'mapper.readValue(jsonString,ProductFlavorA.class)'或'mapper.readValue(jsonString,new TypeReference >(){})一樣提供它'取決於productFlavor是具體類還是一般類型。如果您需要在知道該類型之前檢查JSON內的屬性,那麼它變得更加複雜。你可能會使用'@ JsonTypeInfo'和'@ JsonSubTypes'來實現這一點。閱讀[本文](http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html)瞭解更多詳情。 –

+0

這個問題並不是真正的多態性......這就是說,對於不同的變體,數據會以黑客的方式使用(它由其他人擁有,無法修復),例如,對於productFlavor1,info的值可能這是一個產品「,但對於productFlavor2,它可能是'」size1:12; size2:25「',在這種情況下,它需要解析並放入'Size'對象。這很煩人,但我對此無能爲力。所以我真的很喜歡''mapper.readValue(jsonString,Product.class,Builder1.class)''。 –