2014-12-19 12 views
7

Próbuję przekonwertować ciąg Json na ogólny obiekt Java, ze schematem Avro.Json String to Java Object Avro

Poniżej znajduje się mój kod.

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); 

otrzymuję "org.apache.avro.AvroTypeException: Spodziewane rozpoczęcie unii Got VALUE_NUMBER_FLOAT." Wyjątek.

Ten sam kod działa, jeśli nie mam związków w schemacie. Czy ktoś może wyjaśnić i dać mi rozwiązanie.

+0

Z http://avro.apache.org/docs/1.7.6/spec.html#json_encoding, rozumiem, że kodowanie Jsona dla związków jest inne, ale próbuję dowiedzieć się, czy istnieje jakakolwiek metoda, dzięki której Mogę konwertować ciąg json do obiektu. –

+1

FYI, przeciążenie 'jsonDecoder()' akceptuje ciąg json; nie ma potrzeby przekształcania go w strumień. – jaco0646

Odpowiedz

0

Twój schemat nie pasuje do schematu łańcucha json. Musisz mieć inny schemat, który nie ma związku w miejscu błędu, ale liczbę dziesiętną. Taki schemat powinien być następnie używany jako schemat piszący, podczas gdy można swobodnie używać drugiego jako schematu czytnika.

+0

Ewentualnie powiedz Avro, którego używasz, w ten sposób: 'String json =" {\ "foo \": {\ "double \": 30.1}, \ "bar \": {\ "double \" : 60.2}} ";' – Keegan

+0

W ten sposób avro serializuje rekord z podanym schematem. – miljanm

+0

Dzięki Miljanm i Keegan. Tak, rozumiem, że kodowanie json dla związków różni się od avro.apache.org/docs/1.7.6/spec.html#json_encoding. Ale szukałem biblioteki open source, która może wewnętrznie zmienić ciąg znaków json na specyficzny schemat avro, a następnie przeanalizować go. czy coś takiego jest dostępne? –

6

Dzięki Reza. Znalazłem tę stronę. Wprowadzono sposób konwertowania ciągu Json na obiekt avro.

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

Kluczowym jego kod jest:

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

Ten kod nie rozwiąże problemu. To nie działa, gdy schemat zawiera związki. – deepak

3

Z Avro 1.4.1, to działa:

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); 
} 

może potrzebować kilka poprawek nowszych wersjach Avro.