【问题标题】:Prevent GroovyDefaultMethods join() from shadowing join() method of Java class?防止 GroovyDefaultMethods join() 遮蔽 Java 类的 join() 方法?
【发布时间】:2019-05-31 21:03:22
【问题描述】:

我正在尝试在 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...-

我认为正在发生的事情是 TableIterable<Row> 所以也许 Groovy 正在接受 its own join method

真正奇怪的是,如果我将 Tablesaw 版本从 0.32.6 切换到 0.24.9,即使 Table also implements Iterable<Row> in that version 也能正常工作

知道如何强制 Groovy 使用 Tablesaw 库中的 join 方法而不是它自己的 join 方法吗?

【问题讨论】:

标签: groovy


【解决方案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 使用其 join() 方法增强了 Iterable<T> 类,但它的原型如下:

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")

但是,在单个字符串参数的情况下,由于两个重载方法的定义,您需要做出明确的参数选择。

【讨论】:

    【解决方案2】:

    根据另一个答案,这种特殊情况可以通过在方法调用中使用显式类型来解决。这里只是有关 GroovyDefaultMethod 覆盖的一般主题的更多背景信息。

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

    • how do methods in DefaultGroovyMethods get applied?

      所以当我们创建 ArrayList 元类时,我们检查 ArrayList 类,从中获取所有方法并创建我们的元方法 出它。然后我们得到 DGM 方法列表并应用所有方法 他们的取决于继承..."

      这可以解释为什么使用不同的 Tablesaw 版本会得到不同的结果,具体取决于来自 Iterable 的确切继承细节。

    • Override a method from DefaultGroovyMethods

      如果您想在脚本期间执行此操作,您可以使用 每个实例的元类要做:

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

    由此我相信你可以修改Table的元类来使用你想要使用的方法。由于 DefaultGroovyMethods 的应用也依赖于继承细节,你也可以尝试子类化 Table。

    metaprogramming docs 也可能有帮助。

    【讨论】:

    • 在这种情况下不需要使用元编程。这只是join(String separator) 方法被join(String... columnNames) 重载的极端情况,因此如果您想选择使用可变参数的重载版本,则需要明确参数类型。
    • 请留下答案 :-) 我发现附加信息非常有帮助!并且答案允许比 cmets 更多的格式
    猜你喜欢
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 2015-08-05
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多