如何使用Scala 2.8将String * scala vararg传递给java方法

时间:2010-10-04 15:11:27

标签: scala

我想从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)

2 个答案:

答案 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