web-dev-qa-db-fra.com

Chaîne Json à Java Object Avro

J'essaie de convertir une chaîne Json en un objet générique Java, avec un schéma Avro.

Voici mon code.

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

J'obtiens l'exception "org.Apache.avro.AvroTypeException: union de démarrage attendue. Obtention de VALUE_NUMBER_FLOAT".

Le même code fonctionne, si je n'ai pas d'unions dans le schéma. Quelqu'un peut-il expliquer et me donner une solution.

15
Princey James

Votre schéma ne correspond pas au schéma de la chaîne json. Vous devez avoir un schéma différent qui n'a pas une union à la place de l'erreur mais un nombre décimal. Un tel schéma doit ensuite être utilisé comme un schéma d'écriture tandis que vous pouvez utiliser librement l'autre comme schéma de lecture.

0
miljanm

Merci à Reza. J'ai trouvé cette page Web. Il présente comment convertir une chaîne Json en un objet avro.

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

La clé de son code est:

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

Pour tous ceux qui utilisent Avro - 1.8.2, JsonDecoder n'est pas directement instanciable en dehors du package org.Apache.avro.io maintenant. Vous pouvez utiliser DecoderFactory pour cela, comme indiqué dans le code suivant:

String schemaStr = "<some json schema>";
String genericRecordStr = "<some json record>";
Schema.Parser schemaParser = new Schema.Parser();
Schema schema = schemaParser.parse(schemaStr);
DecoderFactory decoderFactory = new DecoderFactory();
Decoder decoder = decoderFactory.jsonDecoder(schema, genericRecordStr);
DatumReader<GenericData.Record> reader =
            new GenericDatumReader<>(schema);
GenericRecord genericRecord = reader.read(null, decoder);
11
Raman

Avec Avro 1.4.1, cela fonctionne:

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

Pourrait avoir besoin de quelques ajustements pour les versions ultérieures d'Avro.

6
Valloric