[英]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.