Consumidor JSON de objects polimórficos

Estou analisando JSON e estou tendo dificuldades com uma estrutura que pode ter uma de três formas. No meu caso, poderia ser zero-dimensional, unidimensional ou bidimensional. Existe alguma maneira de eu poder inspecionar o JSON rapidamente para determinar qual deles é? Ou talvez consuma-o de qualquer maneira e descubra o que é depois.

As estruturas se parecem com isso e podem ser incorporadas em outras estruturas.

"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" ]] } 

O que eu posso estar procurando é uma class genérica que Jackson sempre vai combinar.

Algo como traduzir:

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

Para dentro:

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

Existe uma class AClass eu posso definir que poderia ser um destinatário universal para qualquer estrutura ou matriz JSON?

Graças ao comentário de Eric me apontando para programmerbruce eu consegui decifrá-lo. Aqui está o código que usei (reduza para simplificar).

 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 { public InfoDeserializer() { super(Info.class); } @Override public Info deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { Class 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); } } 

E para instalar isso no 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); 

Essa estrutura é o que você quer para o AClass?

 class Dimension { String name; List possibleValues; } class Product { String name; List dimensions; } 

Tudo o que você precisa fazer é alterar o tamanho da lista de dimensions para contabilizar os três tipos.

A análise torna-se um problema trivial de verificar se a propriedade Dimensions está presente no JSON e, em caso afirmativo, iterar sobre ela e append à lista de dimensions .


Outra ideia seria reestruturar o JSON (se puder) de tal forma que todos os casos sejam da mesma forma:

 "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" ] } }