es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo deserializar una matriz JSON con diferentes tipos?

Tengo una matriz JSON como esta:

[
  "0",
  {
    "number": 1,
    "field": "value"
  },
  {
    "number": 2,
    "field": "value"
  }
]

El primer elemento de la matriz es una cadena.

¿Es posible deserializarlo con FasterXML Jackson?

Sé cómo hacerlo con diferentes objetos.
Necesito usar @JsonSubTypes (Aquí hay un ejemplo https://stackoverflow.com/a/38877862/2564509)

El problema con esta matriz es que el primer elemento es de tipo String.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, es posible deserializar este array JSON utilizando FasterXML Jackson. Como se mencionó, el primer elemento del array es una cadena, que debe ser manejada por separado del resto de los elementos del array.

    Una forma de lograr esto es utilizando @JsonSubTypes para especificar las diferentes subclases a las que puede pertenecer el objeto JSON. Por ejemplo, podemos definir una clase base y dos subclases de la siguiente manera:

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
    @JsonSubTypes({
            @JsonSubTypes.Type(value = StringItem.class, name = "string"),
            @JsonSubTypes.Type(value = NumberItem.class, name = "number")}
    )
    public abstract class Item {
        // propiedades y métodos comunes
    }
    
    public class StringItem extends Item {
        private String value;
        // getters and setters
    }
    
    public class NumberItem extends Item {
        private int number;
        private String field;
        // getters and setters
    }
    

    Ahora, podemos crear un deserializador personalizado para el array JSON que comprueba el tipo del primer elemento y deserializa el resto del array en consecuencia. Aquí tienes un ejemplo:

    public class ItemArrayDeserializer extends StdDeserializer<item[]> {
        public ItemArrayDeserializer() {
            this(null);
        }
    
        public ItemArrayDeserializer(Class<?> vc) {
            super(vc);
        }
    
        @Override
        public Item[] deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            List<item> items = new ArrayList<>();
            JsonNode node = jp.getCodec().readTree(jp);
            // comprobar el tipo del primer elemento
            if (node.isArray() && node.size() > 0 && node.get(0).isTextual()) {
                String type = node.get(0).asText();
                // eliminar el primer elemento del array
                node = node.get(1);
                if ("0".equals(type)) {
                    // deserializar el resto del array como StringItems
                    if (node.isArray()) {
                        for(JsonNode itemNode : node) {
                            StringItem item = jp.getCodec().treeToValue(itemNode, StringItem.class);
                            items.add(item);
                        }
                    } else {
                        StringItem item = jp.getCodec().treeToValue(node, StringItem.class);
                        items.add(item);
                    }
                } else {
                    // deserializar el resto del array como NumberItems
                    ObjectMapper mapper = new ObjectMapper();
                    mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                    NumberItem[] numberItems = mapper.treeToValue(node, NumberItem[].class);
                    items.addAll(Arrays.asList(numberItems));
                }
            }
            return items.toArray(new Item[items.size()]);
        }
    }
    

    Este deserializador primero verifica el tipo del primer elemento del array JSON. Si es una cadena “0”, deserializa el resto del array como objetos StringItem. De lo contrario, deserializa el resto del array como objetos NumberItem utilizando un ObjectMapper separado.

    Podemos aplicar este deserializador personalizado al array JSON anotando el campo del array con @JsonDeserialize(using = ItemArrayDeserializer.class):

    public class ItemArray {
        @JsonDeserialize(using = ItemArrayDeserializer.class)
        private Item[] items;
        // getters and setters
    }
    

    Ahora, podemos deserializar el array JSON de la siguiente manera:

    java
    ObjectMapper mapper = new ObjectMapper();
    ItemArray itemArray = mapper.readValue(jsonString, ItemArray.class);
    </item[]>

Comments are closed.