2010-10-04 9 views
5

quisiera llamar al siguiente método Java desde Scala:cómo pasar una scala vararg String * a un método Java utilizando Scala 2,8

protected final FilterKeyBindingBuilder filter(String urlPattern, String... morePatterns) { 
    return filtersModuleBuilder.filter(Lists.newArrayList(urlPattern, morePatterns)); 
} 

mi Scala persona que llama se ve así

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

esto compila, sin embargo, la ejecución del código da una excepción:

java.lang.ClassCastException: scala.collection.mutable.WrappedArray$ofRef cannot be cast to [Ljava.lang.String; 

también probé esto:

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

en este caso la excepción fue:

java.lang.ClassCastException: scala.collection.mutable.ArrayBuffer cannot be cast to [Ljava.lang.String; 

pensé que en 2.8 Array [String] se pasa a java como cadena array [] y no unboxing extra es necesario.

¿Alguna idea?

¡Gracias de antemano!

EDIT:

cómo replicarlo:

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 

resultado:

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) 

Respuesta

7

acabo intentado reproducir el error utilizando Scala 2.8.0 y no puedo. Aquí está mi código

// 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:_*) 
    } 
} 

me sale el siguiente resultado:

class scala.collection.mutable.WrappedArray$ofRef 
class [Ljava.lang.String; 

lo que parece que el compilador es la inserción de la conversión correcta para convertir el WrappedArray.ofRef a un String[].

Editar

sólo trató el funcionamiento de su ejemplo. Parece que hay una interacción de los superaccesores en los rasgos con la conversión de varargs de Scala a varargs de Java. Si cambias el rasgo a una clase, funciona.

A partir de la salida descompilada de ScalaServletModule$class, parece que no hace la conversión necesaria de String* a String[] al llamar al superaccesador (línea 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 
+0

Lo probé con su ejemplo, parece que funciona. No estoy seguro de por qué llamar al método de servlet de Guice hace la diferencia. – poko

+0

(agregó un ejemplo) – poko

+0

¡Interesante! Podría reportar esto como un error – poko

2

El enfoque Scala y Java para varargs no coincide: varargs Scala se basan en Seqs (o tan?) Y varargs Java en matrices. ¿Has intentado

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

?

Al menos parece que ha trabajado aquí: Using varargs from Scala

+0

gracias por su respuesta.El tipo String * es WrapperArray y toArray no cambiará eso. entonces esto dará como resultado el primer mensaje de error – poko

+0

Extraño, para mí algo así como 'System.out.printf ("% s% s ", Array (" Hello "," World "): _ *)' funciona bien. – Landei

+0

Tuve la misma pregunta sobre varargs, ¡esta respuesta resolvió mi problema! – Magnus

Cuestiones relacionadas