2010-10-04 12 views
5

vorrei chiamare il seguente metodo Java da Scala:come passare una stringa * scala vararg a un metodo Java utilizzando Scala 2.8

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

mia scala chiamante assomiglia a questo

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

questo compila, tuttavia, l'esecuzione del codice dà un'eccezione:

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

ho provato anche questo:

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

in questo caso l'eccezione era:

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

ho pensato che in 2.8 Array [String] viene passato a java come stringa [] array e non unboxing supplementare è necessario.

Qualche idea?

Grazie in anticipo!

EDIT:

come 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 

risultato:

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) 

risposta

7

che ho appena cercato di riprodurre l'errore utilizzando Scala 2.8.0 e non ci riesco. Ecco il mio codice

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

ottengo il seguente output:

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

modo che appaia come il compilatore sta inserendo la conversione corretta per convertire il WrappedArray.ofRef ad un String[].

Modifica

appena provato in esecuzione il tuo esempio. Sembra un'interazione di superaccessori nei tratti con la conversione di varargs Scala in varargs Java. Se si modifica il tratto di una classe funziona.

Dall'output decompilato di ScalaServletModule$class, sembra che non fa la conversione necessaria da String* a String[] quando si chiama la funzione di accesso super (linea 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

L'ho provato con il tuo esempio sembra funzionare. hmm non sono sicuro del perché chiamare quel metodo di servlet guice fa la differenza. – poko

+0

(aggiunto un esempio) – poko

+0

interessante! Potrei segnalare questo come un bug – poko

2

L'approccio Scala e Java per varargs non corrisponde: varargs Scala si basano su Seqs (o giù di lì?) E varargs Java sugli array. Hai provato

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

?

Almeno questo sembra aver funzionato qui: Using varargs from Scala

+0

grazie per la risposta.Il tipo di stringa * è WrapperArray e toArray non lo cambierà. quindi questo risulterà nel primo messaggio di errore – poko

+0

Strange, per me qualcosa come 'System.out.printf ("% s% s ", Array (" Hello "," World "): _ *)' funziona correttamente. – Landei

+0

Ho avuto la stessa domanda sui vararg, questa risposta ha risolto il mio problema! – Magnus

Problemi correlati