如果avro架构中包含union,如何将json对象转换为Avro对象

时间:2015-10-20 12:09:05

标签: json api avro

给定示例模式包含一个字段,该字段是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和下面描述的代码snipet,

    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)

3 个答案:

答案 0 :(得分:2)

如果使用node.js是一个选项,您可以使用avsc为您进行转换。使用wrapUnions set调用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"
// }

答案 1 :(得分:0)

有一个新的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

答案 2 :(得分:0)

检出该项目:https://github.com/allegro/hermes/pull/749/files

您对JsonAvroConverter感兴趣。它从json(无联合类型)反序列化为Avro生成的对象(具有联合类型)。实际上,它是从并集上的类型模式获得的,并一一尝试。在我们的情况下,效果很好。

正在执行此工作:https://github.com/allegro/json-avro-converter/blob/master/converter/src/main/java/tech/allegro/schema/json2avro/converter/JsonGenericRecordReader.java

致谢!