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 analizar valores sin procesar de elementos de matriz JSON con Jackson?

Al utilizar la deserialización de Jackson, sería genial tener una opción para deserializar un JSON array de elementos (de cualquier tipo: objeto, número, cadena) a un array de Java de String.

Veo que @JsonRawValue permite tener una funcionalidad similar para los campos anidados. ¿Es posible implementar lo mismo para objetos de “nivel superior”?

void test(){
    var payload = """ [
          {"a": 1, "b": "hello"},
          {"a": 2, "b": "bye"},
          "something"
    ]
    """;

    // ¿Qué más se requiere para conseguir el efecto de @JsonRawValue?

    String[] rawItems = new ObjectMapper().readValue(payload, String[].class);

    assertEquals("""{"a": 1, "b": "hello"}""", rawItems[0]);
    assertEquals("""{"a": 2, "b": "bye"}""", rawItems[1]);
    assertEquals("\"something\"", rawItems[2]);
}
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para deserializar una matriz JSON de elementos a una matriz de cadenas Java, podemos usar la anotación @JsonRawValue. Sin embargo, esta anotación solo se aplica a campos anidados y no al objeto de nivel superior. Para implementar la misma funcionalidad para los objetos de nivel superior, necesitamos hacer uso de un JsonDeserializer personalizado.

    El deserializador personalizado debe registrarse con la instancia de ObjectMapper que usamos para deserializar la cadena JSON. Podemos hacer esto llamando al método registerModule en la instancia de ObjectMapper con una nueva instancia de la clase SimpleModule. Luego, anulamos el método deserialize de la clase JsonDeserializer para devolver una matriz de cadenas.

    Aquí hay un ejemplo de código que muestra cómo implementar esto:

    import com.fasterxml.jackson.annotation.JsonRawValue;
    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.module.SimpleModule;
    
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    
    public class Test {
    
        public static void main(String[] args) throws IOException {
            String payload = "[{\"a\": 1, \"b\": \"hello\"}, {\"a\": 2, \"b\": \"bye\"}, \"something\"]";
    
            ObjectMapper objectMapper = new ObjectMapper();
            SimpleModule module = new SimpleModule();
            module.addDeserializer(String[].class, new StringArrayDeserializer());
            objectMapper.registerModule(module);
    
            String[] rawItems = objectMapper.readValue(payload, String[].class);
    
            System.out.println(rawItems[0]); // {"a": 1, "b": "hello"}
            System.out.println(rawItems[1]); // {"a": 2, "b": "bye"}
            System.out.println(rawItems[2]); // "something"
        }
    
        private static class StringArrayDeserializer extends JsonDeserializer<string[]> {
            @Override
            public String[] deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
                List<string> items = new ArrayList<>();
                while (p.nextToken() != null) {
                    if (p.currentToken().isStructStart()) {
                        items.add(p.readValueAsTree().toString());
                    } else if (p.currentToken().isValue()) {
                        items.add(p.getValueAsString());
                    }
                }
                return items.toArray(new String[0]);
            }
        }
    }
    

    En este ejemplo de código, definimos una clase StringArrayDeserializer que extiende la clase JsonDeserializer. Anulamos el método deserialize para leer cada elemento en la matriz JSON y agregarlo a una lista de cadenas. Distinguimos entre objetos y valores verificando el tipo de token actual y usamos el método readValueAsTree para obtener la representación de cadena cruda de objetos.

    Luego registramos este deserializador personalizado con una instancia de ObjectMapper, y lo usamos para deserializar la cadena JSON en una matriz de cadenas. Verificamos que la deserialización funcione como se esperaba imprimiendo cada elemento en la matriz resultante.</string[]>

Comments are closed.