让我们做一个简单的课程。
class IntValue {
private int data;
IntValue() {}
IntValue(int data) { this.setData(data); }
int getData() { return this.data; }
void setData(int data) { this.data = data; }
}
一个很薄的通用包装器:
class Snapshot<T> {
private T value;
Snapshot<T> () {}
T getValue() { return value; }
void setValue(T value) { this.value = value; }
}
接下来让我们帮助获取包装器架构。
private static Schema buildSnapshotSchema(Schema valueSchema) {
return SchemaBuilder.record("Snapshot")
.namespace("com.stackoverflow.primer")
.fields()
.name("value").type(valueSchema).noDefault()
.endRecord();
}
最后,我想创建具有显式架构的AvroCoder,方法与在Using Avrocoder for Custom Types with Generics中创建的方式相同
AvroCoder.of(Snapshot.class, buildSnapshotSchema(AvroCoder.of(IntValue.class).getSchema())
结果......
Exception in thread "main" java.lang.IllegalArgumentException: Unable to get field data from class null
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.getField(AvroCoder.java:710)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.checkRecord(AvroCoder.java:548)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.doCheck(AvroCoder.java:477)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.recurse(AvroCoder.java:453)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.checkRecord(AvroCoder.java:567)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.doCheck(AvroCoder.java:477)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.recurse(AvroCoder.java:453)
at com.google.cloud.dataflow.sdk.coders.AvroCoder$AvroDeterminismChecker.check(AvroCoder.java:430)
at com.google.cloud.dataflow.sdk.coders.AvroCoder.<init>(AvroCoder.java:189)
at com.google.cloud.dataflow.sdk.coders.AvroCoder.of(AvroCoder.java:144)
at com.stackoverflow.primer.GenericPipeline.main(GenericPipeline.java:45)
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 com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)
它发生在AvroDeterminismChecker中,当它无法获得字段&#34;数据&#34;来自Object的一个实例。这是有道理的,但为什么它不使用提供的模式来重建对象?在这种情况下如何创建AvroCoder实例?
更新
发现另一篇有类似问题的帖子,但看起来似乎没有得到解决...... Dataflow output parameterized type to avro file
答案 0 :(得分:2)
我将您的示例复制并粘贴到Apache Beam主分支中的AvroCoderTest代码中,测试不会因此异常而失败:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>org.sample.App</mainClass> // specify your main class here
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</project>
也许问题已得到解决?
答案 1 :(得分:0)
从未使用过AvroCoder,但这也是其他框架中泛型的常见问题。这通常由超类型令牌解决。 AvroCoder有一个采用类型令牌的方法(在这种情况下是TypeDescriptor)。
我没有尝试过这段代码,但它有可能工作。
AvroCoder.of( new TypeDescriptor<Snapshot<InvValue>>(){}).of( buildSnapshotSchema(AvroCoder.of(IntValue.class).getSchema());
答案 2 :(得分:0)
最后的说明: 最高版本1.9 Dataflow SDK 不支持在泛型上使用AvroCoder。当AvroCoder构造函数试图猜测结果是否具有确定性时,会发生错误。
Jule&#39; 16中Apache Beam的问题是resolved。在Apache Beam v0.2孵化之后,AvroCoder 始终为泛型实例化非确定性编码器。由于某些原因,它没有向后移植到Dataflow SDK。根据@jkff建议,我已经为数据流创建了PR。如果维护者决定应用它 - Dataflow SDK v1.10将支持泛型。
好消息是已经有SDK v.2.01-beta,它是Apache Beam v0.4.0的轻量级代理,它支持泛型并且有很多附加功能。转换需要一些代码更新,但绝对值得。