web-dev-qa-db-ja.com

Json String to Java Object Avro

私は、Json文字列を一般的なJavaオブジェクト、Avroスキーマを使用して)に変換しようとしています。

以下は私のコードです。

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

「org.Apache.avro.AvroTypeException:Expected start-union。Got VALUE_NUMBER_FLOAT」例外が発生します。

スキーマにユニオンがなければ、同じコードが機能します。誰かが説明して私に解決策を教えてください。

15
Princey James

スキーマがjson文字列のスキーマと一致しません。エラーの代わりにユニオンではなく10進数を持つ別のスキーマが必要です。そのようなスキーマはライタースキーマとして使用する必要がありますが、他のスキーマはリーダースキーマとして自由に使用できます。

0
miljanm

Rezaに感謝します。このウェブページを見つけました。 Json文字列をavroオブジェクトに変換する方法を紹介します。

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

彼のコードの鍵は:

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

Avro-1.8.2を使用するすべての人にとって、JsonDecoderはパッケージの外部で直接インスタンス化できませんorg.Apache.avro.io現在。次のコードに示すように、DecoderFactoryを使用できます。

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

Avro 1.4.1では、これは機能します。

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

今後のAvroバージョンでは、いくつかの調整が必要になる場合があります。

6
Valloric