如何使Avro模式中的所有字段可为空?

时间:2019-05-12 07:16:08

标签: java avro avro-tools

使Avro模式中的所有字段都可为空的最短,最安全的方法是什么? 当然,我可以使用模式的Json进行操作,就像schema.toString().replaceAll("\"type\": \"long\"", "\"type\": [\"null\", \"long\"]")一样,但这是一个非常丑陋且不安全的解决方案。

1 个答案:

答案 0 :(得分:0)

以下代码将为联合类型添加默认值,并且还将首先将类型与null类型交换。您可以为原始类型添​​加另一个条件,并添加联合类型以及'null'默认值。

import org.apache.avro.JsonProperties;
import org.apache.avro.Schema;

...
String srcSchemaFile = "sample.avsc"; // Source Avro schema file 
String targetSchemaFile = "sample_fixed.avsc"; // Target Avro schema file 
Schema.Parser avroParser = new Schema.Parser();
Schema schema = avroParser.parse(new File(srcSchemaFile));
makeNullable(schema);
PrintWriter writer = new PrintWriter(targetSchemaFile);
writer.write(schema.toString().replaceAll("defaultXXX", "default")); 
writer.close();
...

private static void makeNullable(Schema schema){
    if ( schema.getType() != Schema.Type.NULL){
        for ( Schema.Field field: schema.getFields()){
            if (field.schema().getType() == Schema.Type.UNION){
                int nullIndex = IntStream.range(0, field.schema().getTypes().size())
                        .filter(i -> field.schema().getTypes().get(i).getType() == Schema.Type.NULL )
                        .findFirst().orElse(-1);
                if (nullIndex > 0 && field.defaultVal() == null){
                    // default property is reserved and cannot be added through addProp method, adding defaultXXX to replace later as a workaround
                    field.addProp("defaultXXX", JsonProperties.NULL_VALUE); 
                    Collections.swap(field.schema().getTypes(), 0, nullIndex);
                }
                for (Schema fieldSchema: field.schema().getTypes()){
                    if (fieldSchema.getType() == Schema.Type.RECORD){
                        makeNullable(fieldSchema);
                    } else if (fieldSchema.getType() == Schema.Type.ARRAY){
                        for (Schema elemSchema: fieldSchema.getElementType().getTypes()){
                            if (elemSchema.getType() == Schema.Type.RECORD){
                                makeNullable(elemSchema);
                            }
                        }
                    }
                }
             }
        }
    }
}