2014-06-12 227 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)''。 –