我正在尝试使用Avro Schema将Json字符串转换为通用Java对象。
以下是我的代码。
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);
我得到&#34; org.apache.avro.AvroTypeException:预期的start-union。得到VALUE_NUMBER_FLOAT&#34;异常。
如果我在模式中没有联合,那么相同的代码也可以运行。 有人可以解释并给我一个解决方案。
答案 0 :(得分:10)
感谢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);
答案 1 :(得分:8)
对于使用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);
答案 2 :(得分:6)
使用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版本进行一些调整。
答案 3 :(得分:0)
您的架构与json字符串的架构不匹配。您需要具有不同的模式,该模式在错误的位置没有并集,而是十进制数。然后,这种模式应该用作编写器模式,而您可以自由地使用另一个模式作为读取器模式。
答案 4 :(得分:0)
问题不是代码,而是json的格式错误
String json =“ {” foo“:{” double“:30.1},” bar“:{” double“:60.2}}”;
答案 5 :(得分:0)
正如在评论中已经提到的那样,AVRO 库理解的 JSON 与普通的 JSON 对象有点不同。具体来说,UNION
类型被包装成一个嵌套的对象结构:"union_field": {"type": "value"}
。
因此,如果要将“普通”JSON 转换为 AVRO,则必须使用 3rd-party 库。至少现在是这样。
Java
项目,不确定默认值。Scala
编写,但仍可从 Java
使用。支持联合、默认值、base64 二进制数据...