Estoy tratando de incluir JSON sin procesar dentro de un objeto Java cuando el objeto se (des) serializa usando Jackson. Para probar esta funcionalidad, escribí la siguiente prueba:
public static class Pojo {
public String foo;
@JsonRawValue
public String bar;
}
@Test
public void test() throws JsonGenerationException, JsonMappingException, IOException {
String foo = "one";
String bar = "{\"A\":false}";
Pojo pojo = new Pojo();
pojo.foo = foo;
pojo.bar = bar;
String json = "{\"foo\":\"" + foo + "\",\"bar\":" + bar + "}";
ObjectMapper objectMapper = new ObjectMapper();
String output = objectMapper.writeValueAsString(pojo);
System.out.println(output);
assertEquals(json, output);
Pojo deserialized = objectMapper.readValue(output, Pojo.class);
assertEquals(foo, deserialized.foo);
assertEquals(bar, deserialized.bar);
}
El código genera la siguiente línea:
{"foo":"one","bar":{"A":false}}
El JSON es exactamente como quiero que se vean las cosas. Desafortunadamente, el código falla con una excepción al intentar volver a leer el JSON en el objeto. Esta es la excepción:
org.codehaus.jackson.map.JsonMappingException: no se puede deserializar la instancia de java.lang.String del token START_OBJECT en [Fuente: java.io.StringReader@d70d7a; línea: 1, columna: 13] (a través de la cadena de referencia: com.tnal.prism.cobalt.gather.testing.Pojo ["bar"])
¿Por qué Jackson funciona bien en una dirección pero falla cuando va en la otra dirección? Parece que debería poder tomar su propia salida como entrada nuevamente. Sé que lo que estoy tratando de hacer es poco ortodoxo (el consejo general es crear un objeto interno bar
que tenga una propiedad nombrada A
), pero no quiero interactuar con este JSON en absoluto. Mi código está actuando como un paso a través para este código: quiero tomar este JSON y enviarlo de nuevo sin tocar nada, porque cuando el JSON cambia, no quiero que mi código necesite modificaciones.
Gracias por el consejo.
EDITAR: Hizo de Pojo una clase estática, lo que estaba causando un error diferente.
fuente
Siguiendo la respuesta de @StaxMan , hice los siguientes trabajos como un encanto:
Y, para ser fieles a la pregunta inicial, aquí está la prueba de trabajo:
fuente
getJson()
vuelveString
después de todo. Si solo devuelve elJsonNode
que se estableció a través del configurador, se serializaría como se desea, ¿no?node.asText()
devuelve un valor vacío al ladotoString()
.Pude hacer esto con un deserializador personalizado (cortado y pegado desde aquí )
fuente
@JsonRawValue
@JsonSetter puede ayudar. Vea mi muestra (se supone que los 'datos' contienen JSON sin analizar):
fuente
Además de la gran respuesta de Roy Truelove , así es como inyectar el deserializador personalizado en respuesta a la aparición de :
@JsonRawValue
fuente
Este es un problema con tus clases internas. La
Pojo
clase es una clase interna no estática de su clase de prueba y Jackson no puede crear una instancia de esa clase. Entonces puede serializar, pero no deserializar.Redefine tu clase así:
Tenga en cuenta la adición de
static
fuente
Esta sencilla solución funcionó para mí:
Así que pude almacenar el valor sin procesar de JSON en la variable rawJsonValue y luego no fue un problema deserializarlo (como objeto) con otros campos de vuelta a JSON y enviarlo a través de mi REST. Usar @JsonRawValue no me ayudó porque el JSON almacenado se deserializó como String, no como objeto, y eso no era lo que quería.
fuente
Esto incluso funciona en una entidad JPA:
Idealmente, ObjectMapper e incluso JsonFactory son del contexto y están configurados para manejar su JSON correctamente (estándar o con valores no estándar como flotadores 'Infinity', por ejemplo).
fuente
JsonNode.toString()
documentaciónMethod that will produce developer-readable representation of the node; which may <b>or may not</b> be as valid JSON.
Así que esta es una implementación muy arriesgada.JsonNode.asText()
internamente y generará Infinity y otros valores JSON no estándar.Aquí hay un ejemplo completo de cómo utilizar los módulos de Jackson para que
@JsonRawValue
funcionen en ambos sentidos (serialización y deserialización):Luego puede registrar el módulo después de crear
ObjectMapper
:fuente
org.codehaus.jackson
paquete sin darme cuenta. Asegúrese de que todas sus importaciones provengan decom.fasterxml.jackson
.Yo tuve exactamente el mismo problema. Encontré la solución en esta publicación: Parse JSON tree to plain class usando Jackson o sus alternativas
Mira la última respuesta. Al definir un definidor personalizado para la propiedad que toma un JsonNode como parámetro y llama al método toString en jsonNode para establecer la propiedad String, todo funciona.
fuente
El uso de un objeto funciona bien en ambos sentidos ... Este método tiene un poco de sobrecarga deserializando el valor bruto en dos veces.
RawHello.java
RawJsonValue.java
fuente
Tuve un problema similar, pero usando una lista con muchos itens JSON (
List<String>
).Manejé la serialización usando la
@JsonRawValue
anotación. Pero para la deserialización tuve que crear un deserializador personalizado basado en la sugerencia de Roy.A continuación puede ver mi deserializador "Lista".
fuente