2015-04-24 6 views
7

Sto cercando di utilizzare il parser Jackson Json (v2.5.2) per analizzare un documento json personalizzato che non è vero json e non riesco a capire come fallo funzionare. Ho un documento JSON che potrebbe essere simile:Gestione dell'eccezione "token non riconosciuto" in json personalizzato con Jackson

{ 
    "test": { 
     "one":"oneThing", 
     "two": nonStandardThing(), 
     "three": true 
    } 
} 

voglio usare l'ObjectMapper per mappare ad un java.util.Map e vorrei solo il nonStandardThing() essere aggiunto come un valore stringa nella mia mappa per la chiave two .

Quando ho eseguito questo attraverso il ObjectMapper.readValue(json, Map.class) ottengo l'eccezione:

com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'nonStandardThing': was expecting 'null', 'true', 'false' or NaN 
at [Source: { "test":{"test1":nonStandardThing(),"test2":"two"}}; line: 1, column: 35] 
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1487) 
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:518) 
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2300) 
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2277) 

ho cercato di registrare un DeserializationProblemHandler con la ObjectMapper ma non è mai chiamato quando si verifica questo problema.

Ecco un'applicazione di esempio che mostra ciò che ho provato:

import com.fasterxml.jackson.core.JsonParser; 
import com.fasterxml.jackson.core.JsonProcessingException; 
import com.fasterxml.jackson.databind.DeserializationContext; 
import com.fasterxml.jackson.databind.JsonDeserializer; 
import com.fasterxml.jackson.databind.ObjectMapper; 
import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler; 
import java.io.IOException; 
import java.util.Map; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

public class JacksonDeserializerTest { 
    private Logger log = Logger.getLogger(JacksonDeserializerTest.class.getName()); 
    public JacksonDeserializerTest() { 
     String validJson = "{ \"test\":{\"test1\":\"one\",\"test2\":\"two\"}}"; 
     String invalidJson = "{ \"test\":{\"test1\":nonStandardThing(),\"test2\":\"two\"}}"; 

     ObjectMapper mapper = new ObjectMapper(); 
     mapper.addHandler(new DeserializationProblemHandler() { 
      @Override 
      public boolean handleUnknownProperty(DeserializationContext dc, JsonParser jp, JsonDeserializer<?> jd, Object bean, String property) throws IOException, JsonProcessingException { 
       System.out.println("Handling unknown property: " + property); 
       return false; 
      } 
     }); 

     try { 
      log.log(Level.INFO, "Valid json looks like: {0}", mapper.readValue(validJson, Map.class).toString()); 
      log.log(Level.INFO, "Invalid json looks like: {0}", mapper.readValue(invalidJson, Map.class).toString()); 
     } catch (IOException ex) { 
      log.log(Level.SEVERE, "Error parsing json", ex); 
     } 

    } 

    public static void main(String[] args) { 
     JacksonDeserializerTest test = new JacksonDeserializerTest(); 
    } 
} 

L'output è simile:

Apr 24, 2015 1:40:27 PM net.acesinc.data.json.generator.jackson.JacksonDeserializerTest <init> 
INFO: Valid json looks like: {test={test1=one, test2=two}} 
Apr 24, 2015 1:40:27 PM net.acesinc.data.json.generator.jackson.JacksonDeserializerTest <init> 
SEVERE: Error parsing json 
com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'nonStandardThing': was expecting 'null', 'true', 'false' or NaN 
at [Source: { "test":{"test1":nonStandardThing(),"test2":"two"}}; line: 1, column: 35] 
    at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1487) 
    at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:518) 
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2300) 
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._reportInvalidToken(ReaderBasedJsonParser.java:2277) 
    at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._matchToken(ReaderBasedJsonParser.java:2129) 

Chiunque può segnalare il motivo per cui il gestore non viene mai chiamato? Oppure, se c'è una migliore analisi di questo documento json personalizzato (Jackson o no ...), fammi sapere.

risposta

7

Il gestore non viene chiamato perché la parte non valida non è la proprietà ("two") ma il valore (nonStandardThing()).

Un modo ovvio per gestire questo, è passare nonStandardThing() come String, cioè riscrivere il documento JSON come

{ 
    "test": { 
     "one":"oneThing", 
     "two": "nonStandardThing()", 
     "three": true 
    } 
} 

Se questo non è una possibilità, non c'è molto da fare. L'utilizzo di un'abitudine JacksonDeserializer è utile solo per le proprietà, non per i valori.

+0

E con "Deserializzatore di Jackson" si intende un diserializzatore personalizzato java.util.Map? Questo è quello che mi preoccupava ... –

+1

Nemmeno quello fornirà una soluzione. Dalle discussioni nella mailing list 'Jackson', è chiaro che al momento esistono le funzionalità necessarie per le proprietà, non per i valori. Presumibilmente non hai alcun controllo sul processo di serializzazione? +1 per una domanda interessante comunque. :-) – PNS

+0

Beh, in realtà potrei essere in grado di cambiare questo formato, ma è interessante che 'Jackson' non ti consenta di elaborare i valori. Bummer, perché potrebbe accadere di nuovo. Suppongo che potresti preprocessare il JSON per citare i valori non standard e renderlo valido. In ogni caso, la tua risposta (che in precedenza mi era passata per la testa) mi ha fatto riflettere di nuovo sul problema in modo diverso e ora sto rielaborando le cose per adattarle meglio. Grazie! –

2

I contenuti che elenchi non sono purtroppo validi JSON, quindi quello che hai non è realmente un documento JSON, ma forse la serializzazione di un oggetto Javascript. Tutti i valori di stringa DEVONO essere racchiusi tra virgolette in JSON.

Jackson non supporta la lettura di tale contenuto direttamente, ma potrebbe essere possibile leggerlo utilizzando il parser YAML come SnakeYAML. Jackson ha anche il modulo di formato dati YAML allo https://github.com/FasterXML/jackson-dataformat-yaml/, quindi potresti usarlo. Dato che YAML è (soprattutto!) Un superset di JSON, potrebbe probabilmente fare ciò che vuoi.

+0

Grazie per i suggerimenti sul parser YAML! Dovrò provarlo la prossima volta. –

Problemi correlati