防止GroovyDefaultMethods join()遮盖Java类的join()方法?

时间:2019-05-31 21:03:22

标签: groovy

我正在尝试在Groovy中使用Java库,但是Groovy正在使用其自己的方法覆盖方法名称join之一。

以下代码失败:

%%classpath add mvn
tech.tablesaw tablesaw-core 0.32.6
tech.tablesaw tablesaw-beakerx 0.32.6
com.jimmoores quandl-tablesaw 2.0.0

%import com.jimmoores.quandl.*
%import com.jimmoores.quandl.tablesaw.*
%import tech.tablesaw.api.*

// display Tablesaw tables with BeakerX table display widget
tech.tablesaw.beakerx.TablesawDisplayer.register()

TableSawQuandlSession session = TableSawQuandlSession.create();
Table table1 = session.getDataSet(DataSetRequest.Builder.of("FRED/BCNSDODNS").build());
table1.column("Value").setName("Corporate Credit");
Table table2 = session.getDataSet(DataSetRequest.Builder.of("FRED/CMDEBT").build());
table2.column("Value").setName("Household Credit");
Table result = table1.join("Date").inner(table2, "Date");

错误是:

  

groovy.lang.MissingMethodException:没有方法签名:java.lang.String.inner()适用于参数类型:(tech.tablesaw.api.Table,java.lang.String)

这很奇怪,Table.join(String)返回一个DataFrameJoinerhttps://static.javadoc.io/tech.tablesaw/tablesaw-core/0.32.6/tech/tablesaw/api/Table.html#join-java.lang.String...-

我认为正在发生的事情是Table是一个Iterable<Row>,所以Groovy可能正在使用its own join method

让我真正感到奇怪的是,即使我将Table also implements Iterable<Row> in that version的Tablesaw版本从0.32.6切换到0.24.9,它仍然有效

有什么想法可以迫使Groovy使用Tablesaw库中的join方法而不是它自己的join方法吗?

2 个答案:

答案 0 :(得分:1)

根据其他答案,可以通过在方法调用中使用显式键入来解决此特殊情况。这里只是一些有关GroovyDefaultMethod重写的一般主题的背景信息。

关于此的文档很少。一些旧的电子邮件线程与来自DefaultGroovyMethods的这些方法有关:

  • how do methods in DefaultGroovyMethods get applied?

      

    因此,当我们创建ArrayList元类时,我们检查   ArrayList类,从中获取所有方法,并制作我们的元方法   出来。然后,我们获得DGM方法列表,并在中应用所有方法   他们的依赖于继承 ...”

    这也许可以解释为什么根据Iterable的确切继承详细信息,使用不同的Tablesaw版本会得到不同的结果。

  • Override a method from DefaultGroovyMethods
      

    如果要在脚本执行期间执行此操作,可以使用   每个实例的metaClass要做的事情:

     this.metaClass.println = { Object value ->
          System.out.println "woo $value"
     }
    

据此,我相信您可以修改Table的元类以使用您要使用的方法。由于DefaultGroovyMethods的应用还取决于继承细节,因此您也可以尝试对Table进行子类化。

metaprogramming docs也可能有帮助。

答案 1 :(得分:1)

您遇到了这个问题,因为Table.join()方法的原型如下:

public DataFrameJoiner join(String... columnNames)

来源:https://static.javadoc.io/tech.tablesaw/tablesaw-core/0.32.6/tech/tablesaw/api/Table.html#join-java.lang.String...-

您已经注意到Groovy通过其Iterable<T>方法增强了join()类,但是其原型如下:

public String join(String separator)

来源:http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Iterable.html#join(java.lang.String)

这就是以下情况的原因:

table1.join("Date").inner(table2, "Date");

Groovy解析Iterable<T>.join(String separator)而不是Table类中的方法。它仅与0.24.9版本配合使用,因为它提供了具有以下原型的方法:

public DataFrameJoiner join(String columnName)

来源:https://static.javadoc.io/tech.tablesaw/tablesaw-core/0.24.9/tech/tablesaw/api/Table.html#join-java.lang.String-

因此,在这种情况下,Table.join(String columnName)覆盖了方法Iterable<T>.join(String separator)


解决方案

您可以通过使用显式的String[]参数信息进行调用来解决此问题,因此Groovy会立即选择正确的方法。

table1.join(["Date"] as String[]).inner(table2, "Date")

如果您传递两个字符串以使Groovy选择varargs方法,那么它将没有任何明确的参数类型信息就可以工作。

table1.join("Date", "Something").inner(table2, "Date")

但是,对于单个字符串参数,由于有两种重载方法定义,因此您需要进行显式的参数选择。