2010-10-04 7 views
5

Je voudrais appeler la méthode java suivante à partir scala:comment passer une chaîne * scala vararg à une méthode Java en utilisant Scala 2.8

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

mon appelant scala ressemble à ceci

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

cette compile, cependant, l'exécution du code donne une exception:

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

J'ai aussi essayé ceci:

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

dans ce cas, l'exception était:

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

Je pensais que dans 2.8 Array [chaîne] est passé à Java sous forme de tableau String [] et aucun unboxing supplémentaire est nécessaire.

Des idées?

Merci d'avance!

EDIT:

comment répliquer:

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 

Résultat:

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) 

Répondre

7

J'ai juste essayé de reproduire votre erreur en utilisant Scala 2.8.0 et ne peut pas. Voilà mon code

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

Je reçois la sortie suivante:

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

il semble donc que le compilateur insère la conversion correcte pour convertir le WrappedArray.ofRef à un String[].

Modifier

juste essayé de courir votre exemple. Cela ressemble à une interaction de super-accesseurs dans les traits avec la conversion de varargs Scala en varargs Java. Si vous changez le trait en classe, cela fonctionne. A partir de la sortie décompilée de ScalaServletModule$class, il semble qu'il ne réalise pas la conversion nécessaire de String* à String[] lors de l'appel du super-accesseur (ligne 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

Je l'ai essayé avec votre exemple, il semble fonctionner. hmm ne sais pas pourquoi appeler la méthode de ce servlet de guice fait une différence. – poko

+0

(ajouté un exemple) – poko

+0

intéressant! Je pourrais rapporter ceci comme un bogue – poko

2

L'approche Scala et Java pour varargs ne correspond pas: varargs Scala sont basées sur Seqs (ou alors?) Et Java varargs sur les tableaux. Avez-vous essayé

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

?

Au moins cela semble avoir travaillé ici: Using varargs from Scala

+0

merci pour votre réponse.Le type de String * est WrapperArray et toArray ne changera pas cela. donc cela se traduira par le premier message d'erreur – poko

+0

Étrange, pour moi quelque chose comme 'System.out.printf ("% s% s ", Array (" Bonjour "," Monde "): _ *)' fonctionne bien. – Landei

+0

J'ai eu la même question à propos de varargs, cette réponse a résolu mon problème! – Magnus

Questions connexes