2012-09-16 50 views
3

我解析JSON和我有一种结构可以有三种形式之一的困难。在我的情况下,它可能是零维的,一维的或二维的。有没有什么方法可以检查JSON以确定它是哪一个?或者也许消费它,然后研究它是什么。JSON消费者的多态对象

结构看起来像这样,可以嵌入到其他结构中。

"details":{ 
    "Product":"A zero-dimensional Product" 
}, 

"details":{ 
    "Product":"A one-dimensional Product", 
    "Dimensions": [ "Size" ], 
    "Labels": [ "XS", "S", "M", "L" ] 
}, 

"details":{ 
    "Product":"A two-dimensional Product", 
    "Dimensions": [ "Size", "Fit" ], 
    "Labels": [[ "XS", "S", "M", "L" ],[ "26", "28", "30", "32" ]] 
} 

我可能在寻找的是一个通用的类,杰克逊将永远匹配。

喜欢的东西翻译:

{ 
"SomeField": "SomeValue", 
... 
"details":{ 
    ... 
} 
} 

分为:

class MyClass { 
    String SomeField; 
    ... 
    AClass details; 
} 

有一类AClass我可以定义可能是任何JSON结构或阵列的通用接收者?

+0

但是是不是该尺寸和标签都只是可选?否则这是普通的解析? –

+0

试试这个链接:http://stackoverflow.com/questions/2487841/jquery-parse-json-multidimensional-array –

+0

我可能被误解了。我编辑了这个问题来改进(我希望)。关键是该结构可以是三种不同风味中的任何一种。我认为我需要预先尝试JSON来确定它的味道,或者消费任何类型的结构,然后再查找。 – OldCurmudgeon

回答

2

由于Eric的评论指向我programmerbruce我设法破解它。这是我使用的代码(简化为简化)。

public static class Info { 
    @JsonProperty("Product") 
    public String product; 
    // Empty in the 0d version, One entry in the 1d version, two entries in the 2d version. 
    @JsonProperty("Dimensions") 
    public String[] dimensions; 

} 

public static class Info0d extends Info { 
} 

public static class Info1d extends Info { 
    @JsonProperty("Labels") 
    public String[] labels; 
} 

public static class Info2d extends Info { 
    @JsonProperty("Labels") 
    public String[][] labels; 
} 

public static class InfoDeserializer extends StdDeserializer<Info> { 
    public InfoDeserializer() { 
    super(Info.class); 
    } 

    @Override 
    public Info deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { 
    Class<? extends Info> variantInfoClass = null; 
    ObjectMapper mapper = (ObjectMapper) jp.getCodec(); 
    ObjectNode root = (ObjectNode) mapper.readTree(jp); 
    // Inspect the `diemnsions` field to decide what to expect. 
    JsonNode dimensions = root.get("Dimensions"); 
    if (dimensions == null) { 
     variantInfoClass = Info0d.class; 
    } else { 
     switch (dimensions.size()) { 
     case 1: 
      variantInfoClass = Info1d.class; 
      break; 

     case 2: 
      variantInfoClass = Info2d.class; 
      break; 
     } 
    } 
    if (variantInfoClass == null) { 
     return null; 
    } 
    return mapper.readValue(root, variantInfoClass); 
    } 
} 

而且在ObjectMapper安装此:

// Register the special deserializer. 
InfoDeserializer deserializer = new InfoDeserializer(); 
SimpleModule module = new SimpleModule("PolymorphicInfoDeserializerModule", new Version(1, 0, 0, null)); 
module.addDeserializer(Info.class, deserializer); 
mapper.registerModule(module); 
factory = new JsonFactory(mapper); 
2

这是你想要的AClass结构吗?

class Dimension { 
    String name; 
    List<String> possibleValues; 
} 

class Product { 
    String name; 
    List<Dimension> dimensions; 
} 

所有你需要做的是改变dimensions列表的长度占了三种类型。

解析成为检查JSON中是否存在Dimensions属性的一个微不足道的问题,如果是,请遍历它并追加到dimensions列表。


另一个想法是重组JSON(如果可以的话),使得所有的情况都是一样的形式:

"d0":{ 
    "Product":"A zero-dimensional Product", 
    "Dimensions": {} 
}, 

"d1":{ 
    "Product":"A one-dimensional Product", 
    "Dimensions": { 
     "Size": [ "XS", "S", "M", "L" ] 
    } 
}, 

"d2":{ 
    "Product":"A two-dimensional Product", 
    "Dimensions": { 
     "Size": [ "XS", "S", "M", "L" ], 
     "Fit": [ "26", "28", "30", "32" ] 
    } 
} 
+0

好主意,不幸的是我发现你不能用JSON命名数组。 '“大小”:[“XS”,“S”,“M”,“L”]'无效。我还没有完成你的第一个解决方案。 – OldCurmudgeon

+0

嗯,你可以“命名”一个数组?它[验证](http://jsonlint.com/)对我来说很好... – Eric

+0

不,不,重构JSON应该是最后的手段。我宁愿在我的最后解决一个解决方案。 – OldCurmudgeon