我想从scala调用以下java方法:
protected final FilterKeyBindingBuilder filter(String urlPattern, String... morePatterns) {
return filtersModuleBuilder.filter(Lists.newArrayList(urlPattern, morePatterns));
}
我的scala来电看起来像这样
def test(url: String, urls: String*) {
filter(url, urls: _*).through(classOf[MyTestWhateverFilter])
}
这个编译但是,执行代码会产生异常:
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String;
我也试过这个:
def test(url: String, urls: String*) {
filter(url, urls.map(_.asInstanceOf[java.lang.String]) :_*).through(classOf[MyTestWhateverFilter])
}
在这种情况下,例外是:
java.lang.ClassCastException: scala.collection.mutable.ArrayBuffer cannot be cast to [Ljava.lang.String;
我认为在2.8中,Array [String]作为String []数组传递给java,并且不需要额外的拆箱。
有什么想法吗?
提前致谢!
修改
如何复制它:
import com.google.inject.servlet.ServletModule
trait ScalaServletModule extends ServletModule{
def test(s: String,strs: String*) = {
println(strs.getClass)
println(super.filter(s,strs:_*))
}
}
object Test {
def main(args: Array[String]) {
val module = new ServletModule with ScalaServletModule
module.test("/rest")
}
}
/opt/local/lib/scala28/bin/scala -cp /Users/p.user/Downloads/guice-2.0/guice-2.0.jar:/Users/p.user/Downloads/guice-2.0/guice-servlet-2.0.jar:/Users/p.user/Downloads/guice-2.0/aopalliance.jar:/Users/p.user/Downloads/javax.jar/javax.jar:. Test
结果:
class scala.collection.mutable.WrappedArray$ofRef
java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String;
at ScalaServletModule$class.test(test.scala:6)
at Test$$anon$1.test(test.scala:11)
at Test$.main(test.scala:12)
at Test.main(test.scala)
答案 0 :(得分:7)
我刚尝试使用Scala 2.8.0重现您的错误,但不能。这是我的代码
// Example.java
public class Example {
public static void test(String... args) {
System.out.println(args.getClass());
}
}
// In test.scala
object Test {
def main(args: Array[String]) {
test("1", "2", "3")
}
def test(strs: String*) = {
println(strs.getClass)
Example.test(strs:_*)
}
}
我得到以下输出:
class scala.collection.mutable.WrappedArray$ofRef
class [Ljava.lang.String;
所以看起来编译器正在插入正确的转换以将WrappedArray.ofRef
转换为String[]
。
修改强>
试着运行你的例子。它看起来像特征中的超级访问者与将Scala varargs转换为Java varargs的一些交互。如果你将特性改为一个类就可以了。
从ScalaServletModule$class
的反编译输出看,它在调用超级访问器(第19行)时无法从String*
转换为String[]
。
public static void test(ScalaServletModule, java.lang.String, scala.collection.Seq);
Code:
0: getstatic #11; //Field scala/Predef$.MODULE$:Lscala/Predef$;
3: aload_2
4: invokevirtual #18; //Method java/lang/Object.getClass:()Ljava/lang/Class;
7: invokevirtual #22; //Method scala/Predef$.println:(Ljava/lang/Object;)V
10: getstatic #11; //Field scala/Predef$.MODULE$:Lscala/Predef$;
13: aload_0
14: aload_1
15: aload_2
16: checkcast #24; //class "[Ljava/lang/String;"
19: invokeinterface #30, 3; //InterfaceMethod ScalaServletModule.ScalaServletModule$$super$filter:(Ljava/lang/String;[Ljava/lang/String;)Lcom/google/inject/servlet/ServletModule$FilterKeyBindingBuilder;
24: invokevirtual #22; //Method scala/Predef$.println:(Ljava/lang/Object;)V
27: return
答案 1 :(得分:2)
varargs的Scala和Java方法不匹配:Scala varargs基于Seqs(或者左右?)和数组上的Java varargs。你试过吗
filter(url, urls.toArray:_*).through(classOf[MyTestWhateverFilter])
至少这似乎在这里起作用:Using varargs from Scala