2014-12-19 8 views
7

Sto provando a convertire una stringa Json in un oggetto Java generico, con uno schema Avro.Oggetto JSON da stringa a Java Avro

Di seguito è riportato il mio codice.

String json = "{\"foo\": 30.1, \"bar\": 60.2}"; 
String schemaLines = "{\"type\":\"record\",\"name\":\"FooBar\",\"namespace\":\"com.foo.bar\",\"fields\":[{\"name\":\"foo\",\"type\":[\"null\",\"double\"],\"default\":null},{\"name\":\"bar\",\"type\":[\"null\",\"double\"],\"default\":null}]}"; 

InputStream input = new ByteArrayInputStream(json.getBytes()); 
DataInputStream din = new DataInputStream(input); 

Schema schema = Schema.parse(schemaLines); 

Decoder decoder = DecoderFactory.get().jsonDecoder(schema, din); 

DatumReader<Object> reader = new GenericDatumReader<Object>(schema); 
Object datum = reader.read(null, decoder); 

ottengo "org.apache.avro.AvroTypeException: atteso avvio dell'unione Got VALUE_NUMBER_FLOAT." Eccezione.

Lo stesso codice funziona, se non ho unioni nello schema. Qualcuno può spiegarmi e darmi una soluzione.

+0

Da http://avro.apache.org/docs/1.7.6/spec.html#json_encoding, capisco che la codifica Json per i sindacati è diversa, ma sto cercando di capire se c'è un modo, con quale Posso convertire la stringa JSON in oggetto. –

+1

FYI, un sovraccarico di 'jsonDecoder()' accetta una stringa json; non è necessario convertirlo in un flusso. – jaco0646

risposta

0

Lo schema non corrisponde allo schema della stringa json. È necessario disporre di uno schema diverso che non abbia un'unione al posto dell'errore ma un numero decimale. Tale schema dovrebbe quindi essere utilizzato come schema di scrittura mentre è possibile utilizzare liberamente l'altro come schema del lettore.

+0

In alternativa, indica ad Avro quale stai utilizzando, ad esempio: 'String json =" {\ "foo \": {\ "double \": 30.1}, \ "bar \": {\ "double \" : 60.2}} ";' – Keegan

+0

Questo sarebbe il modo in cui avro serializzerebbe il record con lo schema dato. – miljanm

+0

Grazie Miljanm e Keegan. Sì, ho capito che la codifica JSON per le unioni è diversa da avro.apache.org/docs/1.7.6/spec.html#json_encoding. Ma stavo cercando una libreria open source, che potesse cambiare la mia stringa json internamente allo schema avro specifico e poi analizzarla. è qualcosa del genere disponibile? –

6

Grazie a Reza. Ho trovato questa pagina web. Introduce come convertire una stringa Json in un oggetto avro.

http://rezarahim.blogspot.com/2013/06/import-org_26.html

La chiave del suo codice è:

static byte[] fromJsonToAvro(String json, String schemastr) throws Exception { 
    InputStream input = new ByteArrayInputStream(json.getBytes()); 
    DataInputStream din = new DataInputStream(input); 

    Schema schema = Schema.parse(schemastr); 

    Decoder decoder = DecoderFactory.get().jsonDecoder(schema, din); 

    DatumReader<Object> reader = new GenericDatumReader<Object>(schema); 
    Object datum = reader.read(null, decoder); 

    GenericDatumWriter<Object> w = new GenericDatumWriter<Object>(schema); 
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 

    Encoder e = EncoderFactory.get().binaryEncoder(outputStream, null); 

    w.write(datum, e); 
    e.flush(); 

    return outputStream.toByteArray(); 
} 

String json = "{\"username\":\"miguno\",\"tweet\":\"Rock: Nerf paper, scissors is fine.\",\"timestamp\": 1366150681 }"; 

String schemastr ="{ \"type\" : \"record\", \"name\" : \"twitter_schema\", \"namespace\" : \"com.miguno.avro\", \"fields\" : [ { \"name\" : \"username\", \"type\" : \"string\", \"doc\" : \"Name of the user account on Twitter.com\" }, { \"name\" : \"tweet\", \"type\" : \"string\", \"doc\" : \"The content of the user's Twitter message\" }, { \"name\" : \"timestamp\", \"type\" : \"long\", \"doc\" : \"Unix epoch time in seconds\" } ], \"doc:\" : \"A basic schema for storing Twitter messages\" }"; 

byte[] avroByteArray = fromJsonToAvro(json,schemastr); 

Schema schema = Schema.parse(schemastr); 
DatumReader<Genericrecord> reader1 = new GenericDatumReader<Genericrecord>(schema); 

Decoder decoder1 = DecoderFactory.get().binaryDecoder(avroByteArray, null); 
GenericRecord result = reader1.read(null, decoder1); 
+0

Questo codice non risolverà il problema. Questo non funziona quando lo schema contiene i sindacati. – deepak

3

Con Avro 1.4.1, questo funziona:

private static GenericData.Record parseJson(String json, String schema) 
    throws IOException { 
    Schema parsedSchema = Schema.parse(schema); 
    Decoder decoder = new JsonDecoder(parsedSchema, json); 

    DatumReader<GenericData.Record> reader = 
     new GenericDatumReader<>(parsedSchema); 
    return reader.read(null, decoder); 
} 

potrebbe avere bisogno di alcune modifiche per le versioni successive Avro.