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

pok*_*oko 5 scala

我想从scala调用以下java方法:

protected final FilterKeyBindingBuilder filter(String urlPattern, String... morePatterns) {
    return filtersModuleBuilder.filter(Lists.newArrayList(urlPattern, morePatterns));
}
Run Code Online (Sandbox Code Playgroud)

我的scala来电看起来像这样

def test(url: String, urls: String*) {
  filter(url, urls: _*).through(classOf[MyTestWhateverFilter]) 
}
Run Code Online (Sandbox Code Playgroud)

但是,编译时执行代码会产生异常:

java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String;
Run Code Online (Sandbox Code Playgroud)

我也试过这个:

def test(url: String, urls: String*) {
  filter(url, urls.map(_.asInstanceOf[java.lang.String]) :_*).through(classOf[MyTestWhateverFilter]) 
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,例外是:

java.lang.ClassCastException: scala.collection.mutable.ArrayBuffer cannot be cast to [Ljava.lang.String;
Run Code Online (Sandbox Code Playgroud)

我认为在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
Run Code Online (Sandbox Code Playgroud)

结果:

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)
Run Code Online (Sandbox Code Playgroud)

Ben*_*ngs 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:_*)
  }
}
Run Code Online (Sandbox Code Playgroud)

我得到以下输出:

class scala.collection.mutable.WrappedArray$ofRef
class [Ljava.lang.String;
Run Code Online (Sandbox Code Playgroud)

所以看起来编译器正在插入正确的转换以将其转换WrappedArray.ofRef为a String[].

编辑

刚试过运行你的例子.它看起来像是特征中的超级访问者与Scala varargs转换为Java varargs的一些交互.如果您将特征更改为类,则可以使用.

从反编译的输出ScalaServletModule$class,它看起来像它不会做必要的转换String*,以String[]调用超级访问(19行)时.

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
Run Code Online (Sandbox Code Playgroud)