如何在Avro Union逻辑类型字段中指定转换器的默认值?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Avro Union逻辑类型字段中指定转换器的默认值?相关的知识,希望对你有一定的参考价值。

我有以下Avro架构:

{
   "namespace":"com.example",
   "type":"record",
   "name":"BuggyRecord",
   "fields":[
      {
         "name":"my_mandatory_date",
         "type":{
            "type":"long",
            "logicalType":"timestamp-millis"
         },
         "default":1502250227187
      },
      {
         "name":"my_optional_date",
         "type":[
            {
               "type":"long",
               "logicalType":"timestamp-millis"
            },
            "null"
         ],
         "default":1502250227187
      }
   ]
}

我使用maven生成Java文件。 Avro配置:

       <plugin>
            <groupId>org.apache.avro</groupId>
            <artifactId>avro-maven-plugin</artifactId>
            <version>1.8.2</version>
            <executions>
                <execution>
                    <phase>generate-sources</phase>
                    <goals>
                        <goal>schema</goal>
                        <!--<goal>idl-protocol</goal>-->
                    </goals>
                    <configuration>
                        <sourceDirectory>${project.basedir}/src/main/avro</sourceDirectory>
                        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
                        <enableDecimalLogicalType>true</enableDecimalLogicalType>
                        <stringType>String</stringType>
                    </configuration>
                </execution>
            </executions>
        </plugin>

通过mvn compile代码生成的类在一些基本代码上失败:

@Test
public void Foo(){
    BuggyRecord.Builder buggyRecordBuilder = BuggyRecord.newBuilder();
    buggyRecordBuilder.build();
}

错误代码:

org.apache.avro.AvroRuntimeException: java.lang.ClassCastException: java.lang.Long cannot be cast to org.joda.time.DateTime

    at com.example.BuggyRecord$Builder.build(BuggyRecord.java:301)
    at BuggyRecordTest.Foo(BuggyRecordTest.java:10)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to org.joda.time.DateTime
    at com.example.BuggyRecord$Builder.build(BuggyRecord.java:298)
    ... 23 more

我认为是由于Converters没有正确生成:

  private static final org.apache.avro.Conversion<?>[] conversions =
      new org.apache.avro.Conversion<?>[] {
      TIMESTAMP_CONVERSION,
      null,  // <------ THIS ONE IS NOT SET PROPERLY
      null
  };

是我误用代码生成器还是错误?

答案
  {
     "name":"my_optional_date",
     "type":[ "null", {"type" : "long", "logicalType": "timestamp-millis"}], "default": null
  }

解决方法比解决方案更多 - 将“null”类型设置为first,将“default”设置为“default”:null

以上是关于如何在Avro Union逻辑类型字段中指定转换器的默认值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Spring Messaging 中指定处理程序生成的内容类型?

是否通过 C99 中未指定的联合进行类型双关,并且它是否已在 C11 中指定?

是否通过 C99 中未指定的联合进行类型双关,并且它是否已在 C11 中指定?

如何在 MySQL 的子查询中指定父查询字段?

如何在 django 中指定索引类型? (btree 与哈希等)

在构建 Java GraphQL API 时,如何避免从数据库中过度获取(即仅获取查询中指定的字段)?