2011-09-06 16 views
10

estoy serializar y deserializar siguiente objeto de dominio a JSON usando Jackson 1.8.3Jackson deserializar a lo específico tipo primitivo

public class Node { 
    private String key; 
    private Object value; 
    private List<Node> children = new ArrayList<Node>(); 
    /* getters and setters omitted for brevity */ 
} 

objeto es serializado y luego deserializado utilizando el código siguiente

ObjectMapper mapper = new ObjectMapper(); 
mapper.writeValue(destination, rootNode); 

Y luego se deserializó con

mapper.readValue(destination, Node.class); 

Los valores originales del objeto a re o Strings, Doubles, Longs o Booleans. Sin embargo, durante la serialización y la deserialización, Jackson transforma los valores Long (como 4) en enteros.

¿Cómo se puede "forzar" Jackson deserializar valores no numéricos decimales a largo en lugar de enteros?

+0

relacionado: http://stackoverflow.com/questions/3140760/how-to-deserialize-and-cast-to-long-all-numbers – Bozho

+0

Tenga en cuenta que no se puede deserializar un gran valor en Javascript exactamente, porque los números Javascript son siempre puntos flotantes de 64 bits con (solo) mantisa de 52 bits. –

Respuesta

7

Si el tipo se declara como java.lang.Object, Jackson utiliza mapeo 'natural' que utiliza Entero si el valor se ajusta en 32 bits. Además de los manejadores personalizados, debería forzar la inclusión de información de tipo (ya sea agregando @JsonTypeInfo junto a field/getter o habilitando la llamada "tipificación predeterminada").

+0

Este comportamiento no es muy satisfactorio. Significa que cada vez que deserialice un número sin tipo, siempre tendrá que emitirlo y llamar a longValue() o intValue(). Sería genial si Jackson tuviera una forma de forzar a todos los números a Long; al menos el comportamiento sería predecible. – stickfigure

+0

@stickfigure que no sería mucho mejor - teniendo en cuenta que JSON permite que los valores más grande que lo mantiene de 64 bits, por lo que aún se podía conseguir 'BigInteger' (dicho sea de paso, no es' DeserializationFeature.USE_BIG_INTEGER_FOR_INTS' para obligar a todos los números enteros para convertirse a 'BigInteger'). Pero si quieres reglas de coerción específicas, es probable que desees escribir un deserializador personalizado para 'java.lang.Object' y obtener las reglas al 100% de la manera que quieras; todos tienen sus propias preferencias. – StaxMan

+4

Si bien eso puede ser teóricamente cierto, es poco común en la práctica.La mayoría de las aplicaciones Java no utilizan BigInteger, y la mayoría de las aplicaciones Java usan Long para identificadores numéricos. Lo que significa que cada vez que pasas por una situación sin tipo (por ejemplo, un Mapa) necesitas escribir un código como '((Number) map.get (" key ")). LongValue()'. Si le preocupa verificaciones nulas, el código es aún más tedioso. Abrí una solicitud de función en el Repositorio de datos de Jackson. – stickfigure

4

que acabó creando un deserializer personalizada, ya que en mi lógica de la aplicación sólo hay cuatro diferentes tipos de valores (Double, Long, Integer y String).

No estoy seguro si esto es la mejor solución posible, pero funciona por ahora.

public class MyDeserializer extends JsonDeserializer<Object> { 

@Override 
public Object deserialize(JsonParser p, DeserializationContext ctxt) 
     throws IOException, JsonProcessingException { 
    try { 
     Long l = Long.valueOf(p.getText()); 
     return l; 
    } catch (NumberFormatException nfe) { 
     // Not a Long 
    } 
    try { 
     Double d = Double.valueOf(p.getText()); 
     return d; 
    } catch (NumberFormatException nfe) { 
     // Not a Double 
    } 
    if ("TRUE".equalsIgnoreCase(p.getText()) 
      || "FALSE".equalsIgnoreCase(p.getText())) { 
     // Looks like a boolean 
     return Boolean.valueOf(p.getText()); 
    } 
    return String.valueOf(p.getText()); 
    } 
} 
2

He usado algo como lo siguiente para solucionar este problema.

@JsonIgnoreProperties(ignoreUnknown = true) 
public class Message { 
    public Long ID; 

    @JsonCreator 
    private Message(Map<String,Object> properties) { 
     try { 
      this.ID = (Long) properties.get("id"); 
     } catch (ClassCastException e) { 
      this.ID = ((Integer) properties.get("id")).longValue(); 
     } 
    } 
} 
14

Hay una nueva característica en Jackson 2.6 específicamente para este caso:

configurar el ObjectMapper utilizar DeserializationFeature.USE_LONG_FOR_INTS

ver https://github.com/FasterXML/jackson-databind/issues/504

cowtowncoder empujó una confirmación de que se cerró esta edición el 19 de mayo de 2015 Fix # 504 y # 797

Cuestiones relacionadas