2012-11-20 1 views
9

Ho un file JSON che può avere più tipi.Analisi di JSON in Jackson usando un approccio stream/object

Ad esempio:

{ 
    "dog": { 
     "owner" : "John Smith", 
     "name" : "Rex", 
     "toys" : { 
      "chewtoy" : "5", 
      "bone" : "1" 
     } 
    }, 
    "person": { 
     "name" : "John Doe", 
     "address" : "23 Somewhere Lane" 
    } 
    // Further examples of dogs and people, and a few other types. 
} 

Voglio analizzare questi in oggetti. vale a dire. Voglio creare un oggetto Dog con gli attributi proprietario/nome/giocattoli e una persona con gli attributi nome/indirizzo e utilizzare Jackson per leggere e creare oggetti da essi.

L'ordine conta, ho bisogno di sapere che Rex è arrivato prima di John Doe, per esempio. Preferirei fare con un approccio simile al flusso (cioè leggere e analizzare Rex nell'oggetto Dog, fare qualcosa con esso, quindi scartarlo, quindi passare a John Doe). Quindi ho bisogno di un approccio basato sul flusso.

Non riesco a capire come utilizzare sia l'API di lettura del flusso (da passare in ordine), sia l'interfaccia ObjectMapper (per creare oggetti Java da JSON).

+1

(1) La tua domanda sullo streaming o l'analisi simile a SAX è totalmente valida. +1. Ma (2) i tuoi dati non sono ben progettati se ordini argomenti in un dizionario. I dizionari JSON sono intrinsecamente non ordinati. Se hai bisogno di un ordine, usa un array e codifica le informazioni sul tipo (cane/persona) come un attributo. –

+0

Hmm. La fonte dei dati è probabilmente immutabile (non sotto il mio controllo). Quando dici di usare un array e di codificare le informazioni, intendi farlo manualmente? (Leggi tutti i token e crea gli oggetti appropriati chiamando i setter appropriati) O c'è un modo per farlo usando Jackson? –

+0

Intendo dire che i dati JSON dovrebbero venire sotto forma di array se l'ordine è importante, con tipi codificati con ciascun oggetto. Ma se non controlli i dati JSON, allora non importa-- dovrai occuparti dell'analisi del flusso come suggerisci. :) Non ho la risposta alla tua domanda, anche se qualcun altro qui sicuramente lo farà. Ma sappi che chiunque abbia inventato questo formato JSON sta giocando con il fuoco. È molto delicato affidarsi all'ordine delle chiavi in ​​un dizionario, per non parlare del dolore nel culo che crea per le persone (voi) che stanno cercando di affrontarlo - va contro la maggior parte degli strumenti. –

risposta

10

Per fare questo, è necessario utilizzare un mapper oggetto con la vostra fabbrica

import org.codehaus.jackson.JsonFactory; 
import org.codehaus.jackson.JsonParser; 
import org.codehaus.jackson.JsonProcessingException; 
import org.codehaus.jackson.map.ObjectMapper; 
... 
private static ObjectMapper mapper = new ObjectMapper(); 
private static JsonFactory factory = mapper.getJsonFactory(); 

Quindi creare un parser per l'ingresso.

JsonParser parser = factory.createJsonParser(in); 

Ora è possibile combinare le chiamate a parser.nextToken() e scali a parser.readValueAs (classe C). Ecco un esempio che ottiene le classi da una mappa:

Map<String, Class<?>> classMap = new HashMap<String, Class<?>>(); 
classMap.put("dog", Dog.class); 
classMap.put("person", Person.class); 

InputStream in = null; 
JsonParser parser = null; 
List<Object> results = new ArrayList<Object>(); 
try { 
    in = this.getClass().getResourceAsStream("input.json"); 
    parser = factory.createJsonParser(in); 
    parser.nextToken();// JsonToken.START_OBJECT 
    JsonToken token = null; 
    while((token = parser.nextToken()) == JsonToken.FIELD_NAME) { 
    String name = parser.getText(); 
    parser.nextToken(); // JsonToken.START_OBJECT 
    results.add(parser.readValueAs(classMap.get(name))); 
    } 
    // ASSERT: token = JsonToken.END_OBJECT 
} 
finally { 
    IOUtils.closeQuietly(in); 
    try { 
    parser.close(); 
    } 
    catch(Exception e) {} 
} 
+0

Penso di vedere ora. Quando stavo provando a farlo inizialmente, stavo lottando perché non saprei quale oggetto ero a ("cane" o "persona"), ma se i dati sono formattati come una matrice con i valori cane/persona come valori in un attributo "tipo", sarei in grado di farlo. Grazie a tutti. –

+0

Una buona risposta. Ma sarebbe fantastico se tu potessi riscrivere il tuo frammento di codice usando l'ultima libreria di Jackson. –