2011-09-06 19 views
10

sto serializzazione e la deserializzazione seguente oggetto JSON dominio utilizzando Jackson 1.8.3Forzare Jackson di deserializzare a specifiche tipo primitivo

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

oggetto viene serializzato e deserializzato utilizzando seguente codice

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

E poi deserializzato con

mapper.readValue(destination, Node.class); 

I valori originali dell'oggetto a re o stringhe, doppie, lunghe o booleane. Tuttavia, durante la serializzazione e la deserializzazione, Jackson trasforma valori lunghi (come 4) in numeri interi.

Come posso "forzare" Jackson a deserializzare valori numerici non decimali su Long invece di Integer?

+0

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

+0

Attenzione che non è possibile deserializzare un grande valore lungo in Javascript esattamente, perché i numeri Javascript sono sempre a virgola mobile a 64 bit con (solo) mantissa a 52 bit. –

risposta

7

Se tipo è dichiarato come java.lang.Object, Jackson usa la mappatura 'naturale' che utilizza Integer se il valore si inserisce in 32 bit. A parte i gestori personalizzati, dovresti forzare l'inclusione delle informazioni sul tipo (aggiungendo @JsonTypeInfo accanto al campo/getter o abilitando la cosiddetta "digitazione predefinita").

+0

Questo comportamento non è molto soddisfacente. Significa che ogni volta che deserializzi un numero non tipizzato dovrai sempre lanciarlo e chiamare longValue() o intValue(). Sarebbe bello se Jackson avesse un modo per forzare tutti i numeri a Long; almeno il comportamento sarebbe prevedibile. – stickfigure

+0

@stickfigure Non sarebbe molto meglio, tenendo presente che JSON consente valori superiori a quelli a 64 bit, quindi potresti ancora ottenere 'BigInteger' (incidentalmente, c'è' DeserializationFeature.USE_BIG_INTEGER_FOR_INTS' per forzare tutti i numeri interi da convertire in 'BigInteger'). Ma se vuoi delle regole di coercizione specifiche, probabilmente vuoi scrivere un deserializzatore personalizzato per 'java.lang.Object' e ottenere le regole al 100% nel modo in cui le vuoi - ognuno ha le sue preferenze. – StaxMan

+4

Sebbene ciò possa essere teoricamente vero, nella pratica non è comune.La maggior parte delle applicazioni Java non utilizza BigInteger e la maggior parte delle applicazioni Java utilizza Long per gli ID numerici. Il che significa che ogni volta che si passa attraverso una situazione non tipizzata (ad esempio una mappa) è necessario scrivere codice come '((numero) map.get (" chiave ")). LongValue()'. Se sei preoccupato dei controlli null, il codice è ancora più noioso. Ho aperto una richiesta di funzionalità nel repository git databinding di jackson. – stickfigure

4

ho finito per creare un deserializzatore personalizzato, dal momento che nella mia logica dell'applicazione ci sono solo quattro tipi diversi per i valori (Double, Long, Integer e String).

Non sono sicuro se questa sia la soluzione migliore possibile ma funziona per ora.

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

Ho usato qualcosa come il sotto per ovviare a questo 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

C'è una nuova funzionalità di Jackson 2.6 specificamente per questo caso:

Configurare l'ObjectMapper utilizzare DeserializationFeature.USE_LONG_FOR_INTS

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

cowtowncoder spinto un commit che ha chiuso la questione il 19 maggio 2015 Fix # 504 e # 797

Problemi correlati