使用反射调用 Type 参数化方法
Using reflection to invoke Type parameterized methods
google 云数据流 sdk 有一个 class 为不同的 Avro 类型注册编码器。
CoderRegistry cr = p.getCoderRegistry();
cr.registerStandardCoders();
cr.registerCoder(Row.class, AvroCoder.of(Row.class));
cr.registerCoder(Destination.class, AvroCoder.of(Destination.class));
cr.registerCoder(Device.class, AvroCoder.of(Device.class));
cr.registerCoder(Location.class, AvroCoder.of(Location.class));
cr.registerCoder(Source.class, AvroCoder.of(Source.class));
cr.registerCoder(DimensionalMetric.class, AvroCoder.of(DimensionalMetric.class));
cr.registerCoder(DimensionSet.class, AvroCoder.of(DimensionSet.class));
cr.registerCoder(MetricSet.class, AvroCoder.of(MetricSet.class));
但是你可以想象这会变得非常麻烦,我想使用 java 反射 API 自动注册包 com.brightcove.rna.model
中的所有 classes。我想这看起来像这样:
void registerAllModels(Pipeline p) {
CoderRegistry cr = p.getCoderRegistry();
Reflections r = new Reflections("com.brightcove.rna.model");
Set<Class<? extends IndexedRecord>> classes = r.getSubTypesOf(IndexedRecord.class);
for (Class<? extends IndexedRecord> clazz : classes) {
cr.registerCoder(clazz, AvroCoder.of(clazz));
}
}
不幸的是,这不起作用。我在这里做错了什么?
您在以下行中出现编译错误:
cr.registerCoder(clazz, AvroCoder.of(clazz));
错误是:
The method registerCoder(Class<?>, Class<?>) in the type CoderRegistry is not applicable for the arguments (Class<capture#1-of ? extends IndexedRecord>, AvroCoder<capture#2-of ? extends IndexedRecord>).
基本上,问题是 Java 编译器无法推断出两个参数上的通配符类型相同,因此会报告错误。这是一个常见的 Java 问题,例如,参见 this 问题。
修复如下,它可能需要您禁止编译器关于原始类型和未经检查的转换的警告:
cr.registerCoder(clazz, (Coder) AvroCoder.of(clazz.newInstance().getSchema()));
这解决了两个问题:
- 确保使用
registerCoder(Class<T>, Coder<T>)
而不是重载的 registerCoder(Class<?>, Class<?>)
.
AvroCoder.of(Class<T>)
使用 Avro 的 ReflectData.get().getSchema()
生成模式,它可能不适用于所有类型,例如 GenericRecord
。另一种方法是通过 AvroCoder.of(Schema)
构建编码器并从 automatically-generated class. 获取模式
事实证明,更多地阅读我收到的错误消息帮助我找到了问题的根源。
AnalyticsPipeline.java:110: error: no suitable method found for registerCoder(Class<CAP#1>,AvroCoder<CAP#2>)
cr.registerCoder(clazz, AvroCoder.of(clazz));
^
method CoderRegistry.registerCoder(Class<?>,Class<?>) is not applicable
(argument mismatch; no instance(s) of type variable(s) T#1 exist so that AvroCoder<T#1> conforms to Class<?>)
method CoderRegistry.registerCoder(Class<?>,CoderFactory) is not applicable
(argument mismatch; no instance(s) of type variable(s) T#1 exist so that AvroCoder<T#1> conforms to CoderFactory)
method CoderRegistry.<T#2>registerCoder(Class<T#2>,Coder<T#2>) is not applicable
(inferred type does not conform to equality constraint(s)
inferred: CAP#3
equality constraints(s): CAP#3,CAP#1)
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>of(Class<T#1>)
T#2 extends Object declared in method <T#2>registerCoder(Class<T#2>,Coder<T#2>)
where CAP#1,CAP#2,CAP#3 are fresh type-variables:
CAP#1 extends IndexedRecord from capture of ? extends IndexedRecord
CAP#2 extends IndexedRecord from capture of ? extends IndexedRecord
CAP#3 extends IndexedRecord from capture of ? extends IndexedRecord
如上所述,javac 认为参数的类型不匹配(正确,因为我没有提供有关该事实的任何信息)。我的解决方案原来是一个相当简单的修改。通过添加修复类型的辅助函数。
void registerCoders(Pipeline p) {
CoderRegistry cr = p.getCoderRegistry();
Reflections r = new Reflections("com.brightcove.rna.model");
Set<Class<? extends IndexedRecord>> classes = r.getSubTypesOf(IndexedRecord.class);
for (Class<? extends IndexedRecord> clazz : classes) {
registerAvroType(cr, clazz);
}
}
<T extends IndexedRecord> void registerAvroType(CoderRegistry cr, Class<T> clazz) {
cr.registerCoder(clazz, AvroCoder.of(clazz));
}
我能够向编译器传达类型确实相同并且问题已解决。
google 云数据流 sdk 有一个 class 为不同的 Avro 类型注册编码器。
CoderRegistry cr = p.getCoderRegistry();
cr.registerStandardCoders();
cr.registerCoder(Row.class, AvroCoder.of(Row.class));
cr.registerCoder(Destination.class, AvroCoder.of(Destination.class));
cr.registerCoder(Device.class, AvroCoder.of(Device.class));
cr.registerCoder(Location.class, AvroCoder.of(Location.class));
cr.registerCoder(Source.class, AvroCoder.of(Source.class));
cr.registerCoder(DimensionalMetric.class, AvroCoder.of(DimensionalMetric.class));
cr.registerCoder(DimensionSet.class, AvroCoder.of(DimensionSet.class));
cr.registerCoder(MetricSet.class, AvroCoder.of(MetricSet.class));
但是你可以想象这会变得非常麻烦,我想使用 java 反射 API 自动注册包 com.brightcove.rna.model
中的所有 classes。我想这看起来像这样:
void registerAllModels(Pipeline p) {
CoderRegistry cr = p.getCoderRegistry();
Reflections r = new Reflections("com.brightcove.rna.model");
Set<Class<? extends IndexedRecord>> classes = r.getSubTypesOf(IndexedRecord.class);
for (Class<? extends IndexedRecord> clazz : classes) {
cr.registerCoder(clazz, AvroCoder.of(clazz));
}
}
不幸的是,这不起作用。我在这里做错了什么?
您在以下行中出现编译错误:
cr.registerCoder(clazz, AvroCoder.of(clazz));
错误是:
The method registerCoder(Class<?>, Class<?>) in the type CoderRegistry is not applicable for the arguments (Class<capture#1-of ? extends IndexedRecord>, AvroCoder<capture#2-of ? extends IndexedRecord>).
基本上,问题是 Java 编译器无法推断出两个参数上的通配符类型相同,因此会报告错误。这是一个常见的 Java 问题,例如,参见 this 问题。
修复如下,它可能需要您禁止编译器关于原始类型和未经检查的转换的警告:
cr.registerCoder(clazz, (Coder) AvroCoder.of(clazz.newInstance().getSchema()));
这解决了两个问题:
- 确保使用
registerCoder(Class<T>, Coder<T>)
而不是重载的registerCoder(Class<?>, Class<?>)
. AvroCoder.of(Class<T>)
使用 Avro 的ReflectData.get().getSchema()
生成模式,它可能不适用于所有类型,例如GenericRecord
。另一种方法是通过AvroCoder.of(Schema)
构建编码器并从 automatically-generated class. 获取模式
事实证明,更多地阅读我收到的错误消息帮助我找到了问题的根源。
AnalyticsPipeline.java:110: error: no suitable method found for registerCoder(Class<CAP#1>,AvroCoder<CAP#2>)
cr.registerCoder(clazz, AvroCoder.of(clazz));
^
method CoderRegistry.registerCoder(Class<?>,Class<?>) is not applicable
(argument mismatch; no instance(s) of type variable(s) T#1 exist so that AvroCoder<T#1> conforms to Class<?>)
method CoderRegistry.registerCoder(Class<?>,CoderFactory) is not applicable
(argument mismatch; no instance(s) of type variable(s) T#1 exist so that AvroCoder<T#1> conforms to CoderFactory)
method CoderRegistry.<T#2>registerCoder(Class<T#2>,Coder<T#2>) is not applicable
(inferred type does not conform to equality constraint(s)
inferred: CAP#3
equality constraints(s): CAP#3,CAP#1)
where T#1,T#2 are type-variables:
T#1 extends Object declared in method <T#1>of(Class<T#1>)
T#2 extends Object declared in method <T#2>registerCoder(Class<T#2>,Coder<T#2>)
where CAP#1,CAP#2,CAP#3 are fresh type-variables:
CAP#1 extends IndexedRecord from capture of ? extends IndexedRecord
CAP#2 extends IndexedRecord from capture of ? extends IndexedRecord
CAP#3 extends IndexedRecord from capture of ? extends IndexedRecord
如上所述,javac 认为参数的类型不匹配(正确,因为我没有提供有关该事实的任何信息)。我的解决方案原来是一个相当简单的修改。通过添加修复类型的辅助函数。
void registerCoders(Pipeline p) {
CoderRegistry cr = p.getCoderRegistry();
Reflections r = new Reflections("com.brightcove.rna.model");
Set<Class<? extends IndexedRecord>> classes = r.getSubTypesOf(IndexedRecord.class);
for (Class<? extends IndexedRecord> clazz : classes) {
registerAvroType(cr, clazz);
}
}
<T extends IndexedRecord> void registerAvroType(CoderRegistry cr, Class<T> clazz) {
cr.registerCoder(clazz, AvroCoder.of(clazz));
}
我能够向编译器传达类型确实相同并且问题已解决。