【问题标题】:Using reflection to invoke Type parameterized methods使用反射调用 Type 参数化方法
【发布时间】:2015-12-29 03:47:34
【问题描述】:

google cloud dataflow sdk 有一个类可以为不同的 Avro 类型注册 Coders。

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 中的所有类。我想这看起来像这样:

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));
    }
}

很遗憾,这不起作用。我在这里做错了什么?

【问题讨论】:

  • 您能否提供错误信息或描述错误行为?

标签: java reflection google-cloud-dataflow


【解决方案1】:

您在以下行中有编译错误:

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&lt;T&gt;, Coder&lt;T&gt;) 而不是重载的registerCoder(Class&lt;?&gt;, Class&lt;?&gt;)
  • AvroCoder.of(Class&lt;T&gt;) 使用 Avro 的 ReflectData.get().getSchema() 生成模式,可能不适用于所有类型,例如 GenericRecord。另一种方法是通过AvroCoder.of(Schema) 构造编码器并从自动生成的类中获取架构。

【讨论】:

    【解决方案2】:

    事实证明,对我收到的错误消息进行更多阅读有助于我找到问题的根源。

    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));
        }
    

    我能够向编译器传达类型确实相同并且问题已解决。

    【讨论】:

      猜你喜欢
      • 2011-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-03
      • 2012-06-16
      相关资源
      最近更新 更多