在上一篇关于如何将jOOQ与Java 8和Nashorn结合使用的文章之后,我们的一位用户发现了使用jOOQ API的缺陷, 如用户组中所述 。 本质上,缺陷可以总结如下:
Java代码
package org.jooq.nashorn.test;public class API {public static void test(String string) {throw new RuntimeException("Don't call this");}public static void test(Integer... args) {System.out.println("OK");}
}
JavaScript代码
var API = Java.type("org.jooq.nashorn.test.API");
API.test(1); // This will fail with RuntimeException
经过一些调查和Attila Szegedi以及Jim Laskey (来自Oracle的Nashorn开发人员)的友好帮助,很明显,Nashorn消除了重载方法和vararg的歧义,这与旧Java开发人员所期望的有所不同。 报价阿提拉:
Nashorn的重载方法解析尽可能地模仿Java语言规范(JLS),但也允许特定于JavaScript的转换。 JLS说,当选择一种方法来调用重载名称时,仅当没有适用的固定arity方法时,才可以考虑使用可变arity方法进行调用。
我同意只有在没有适用的固定arity方法时才可以考虑使用可变arity方法。 但是,由于使用ToString , ToNumber , ToBoolean进行类型提升(或强制/转换),因此“适用”本身的整个概念已被完全更改,而不是直观上看起来与varargs方法“完全”匹配的对象更喜欢 !
让它沉下去!
既然我们现在知道Nashorn如何解决过载,我们可以看到以下任何一种有效的解决方法:
使用数组参数明确调用test(Integer [])方法:
这是最简单的方法,您可以忽略存在可变参数的事实,而只需创建一个显式数组即可:
var API = Java.type("org.jooq.nashorn.test.API");
API.test([1]);
这样明确地调用test(Integer [])方法:
这无疑是最安全的方法,因为您要消除方法调用中的所有歧义:
var API = Java.type("org.jooq.nashorn.test.API");
API["test(Integer[])"](1);
消除过载:
public class AlternativeAPI1 {public static void test(Integer... args) {System.out.println("OK");}
}
删除可变参数:
public class AlternativeAPI3 {public static void test(String string) {throw new RuntimeException("Don't call this");}public static void test(Integer args) {System.out.println("OK");}
}
提供确切的选择:
public class AlternativeAPI4 {public static void test(String string) {throw new RuntimeException("Don't call this");}public static void test(Integer args) {test(new Integer[] { args });}public static void test(Integer... args) {System.out.println("OK");}
}
用CharSequence(或任何其他“相似类型”)替换String:
现在,这很有趣:
public class AlternativeAPI5 {public static void test(CharSequence string) {throw new RuntimeException("Don't call this");}public static void test(Integer args) {System.out.println("OK");}
}
具体来说,我认为从Java角度来看, CharSequence
和String
类型之间的区别似乎是非常随机的。
商定,即使有可能,也很难用动态类型的语言实现重载的方法解析。 任何解决方案都是一种折衷方案,它将在某些方面引入缺陷。 或正如Attila所说:
如您所见,无论我们做什么,都会遭受其他损失; 重载方法的选择在Java和JS类型系统之间处于紧要关头,并且即使逻辑上的微小变化也非常敏感。
真正! 但是重载方法的选择不仅对很小的变化非常敏感。 也可以将Nashorn与Java互操作性一起使用! 作为API设计师,多年来,我已经习惯了语义版本控制 ,并且在保持API源代码兼容,行为兼容(如果可能)以及很大程度上与二进制兼容的情况下 ,要遵循许多细微的规则。
当您的客户使用Nashorn时,就不用管它了。 他们是自己的。 Java API中新引入的重载可能会严重破坏Nashorn客户端。 但是话又说回来,那是JavaScript,一种在运行时告诉您的语言:
['10','10','10','10'].map(parseInt)
…产量
[10, NaN, 2, 3]
…以及哪里
++[[]][+[]]+[+[]] === "10"
产生真实的! ( 这里的资料 )
有关JavaScript的更多信息, 请访问此入门教程 。
翻译自: https://www.javacodegeeks.com/2014/09/how-nashorn-impacts-api-evolution-on-a-new-level.html