[英]How to convert a json object into Avro object if avro schema contains union in it
给定示例模式包含一个null和string的并集的字段,
{
"type":"record",
"name":"DataFlowEntity",
"namespace":"org.sdf.manage.commons.server",
"fields":
[
{"name":"dataTypeGroupName","type":["null","string"]},
{"name":"dataTypeName","type":"string"},
{"name":"dataSchemaVersion","type":"string"}
]
}
我想转换以下json对象,
{
"dataTypeGroupName": "dg_1",
"dataTypeName": "dt_1",
"dataSchemaVersion": "1"
}
进入与上述模式对应的avro对象。 我尝试使用Avro的JsonDecoder和下面描述的代码snppet,
String dataFlowEntity = "{\"dataTypeGroupName\": \"dg_1\", \"dataTypeName\": \"dt_1\", \"dataSchemaVersion\": \"1\"}";
Schema schema = DataFlowEntity.SCHEMA$;
InputStream inputStream = new ByteArrayInputStream(dataFlowEntity.getBytes());
DataInputStream dInputStream = new DataInputStream(inputStream);
Decoder decoder = DecoderFactory.get().jsonDecoder(schema, dInputStream);
DatumReader<DataFlowEntity> datumReader = new GenericDatumReader<DataFlowEntity>(schema);
DataFlowEntity dataFlowEntityObject = DataFlowEntity.newBuilder().build();
dataFlowEntityObject = datumReader.read(null, decoder);
它失败,例外,
threw exception [org.apache.avro.AvroRuntimeException: org.apache.avro.AvroRuntimeException: Field dataTypeGroupName type:UNION pos:0 not set and has no default value] with root cause
org.apache.avro.AvroRuntimeException: Field dataTypeGroupName type:UNION pos:0 not set and has no default value
at org.apache.avro.generic.GenericData.getDefaultValue(GenericData.java:874)
at org.apache.avro.data.RecordBuilderBase.defaultValue(RecordBuilderBase.java:135)
如果使用node.js是一个选项,您可以使用avsc
为您进行转换。 使用wrapUnions
设置调用clone
会自动将值包装到它们匹配的第一个union分支中。
使用你的例子:
var avsc = require('avsc');
var type = avsc.parse({
"type":"record",
"name":"DataFlowEntity",
"namespace":"org.sdf.manage.commons.server",
"fields": [
{"name":"dataTypeGroupName","type":["null","string"]},
{"name":"dataTypeName","type":"string"},
{"name":"dataSchemaVersion","type":"string"}
]
}, {wrapUnions: true});
var invalidRecord = {
"dataTypeGroupName": "dg_1",
"dataTypeName": "dt_1",
"dataSchemaVersion": "1"
};
var validRecord = type.clone(invalidRecord, {wrapUnions: true});
// == {
// "dataTypeGroupName":{"string":"dg_1"},
// "dataTypeName":"dt_1",
// "dataSchemaVersion":"1"
// }
工作中有一个新的JSON编码器可以解决这个常见问题:
https://issues.apache.org/jira/browse/AVRO-1582
https://github.com/zolyfarkas/avro
这似乎是很多人在与Avro打交道时遇到的常见问题。
如果你将JSON切换到它,它应该工作:
{
"dataTypeGroupName": {"string" : "dg_1"},
"dataTypeName": "dt_1",
"dataSchemaVersion": "1"
}
这是因为Avro使用对象类型包装器对联合进行编码,遗憾的是,甚至是简单的联合来表示不需要JSON对象包装器来消除歧义的可选类型。 Avro的意图似乎永远不会生成友好的JSON,更多的是使用JSON作为序列化格式。
有关更多详细信息,请访问: https : //avro.apache.org/docs/1.7.7/spec.html#json_encoding
检查这个项目: https : //github.com/allegro/hermes/pull/749/files
您对JsonAvroConverter感兴趣。 它从json(没有联合类型)反序列化到Avro生成的对象(具有联合类型)。 实际上,它从union上的类型模式中获取并逐个尝试它们。 它在我们的案例中表现很好。
这是在做这项工作: https : //github.com/allegro/json-avro-converter/blob/master/converter/src/main/java/tech/allegro/schema/json2avro/converter/JsonGenericRecordReader.java
问候!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.