Как передать String * Scala Vararg в метод Java, используя Scala 2.8 - PullRequest
5 голосов
/ 04 октября 2010

Я хотел бы вызвать следующий java-метод из scala:

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]передается в java в виде массива String [] и дополнительная распаковка не требуется.

Есть идеи?

Заранее спасибо!

РЕДАКТИРОВАТЬ:

как его скопировать:

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 ]

7 голосов
/ 04 октября 2010

Я только что попытался воспроизвести вашу ошибку, используя 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 похоже, что он не выполняет необходимое преобразование из 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
2 голосов
/ 04 октября 2010

Подход Scala и Java для varargs не совпадает: varargs Scala основаны на Seqs (или около того?) И varargs Java на массивах. Вы пробовали

filter(url, urls.toArray:_*).through(classOf[MyTestWhateverFilter]) 

По крайней мере, здесь это работает: Использование varargs из Scala

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...