2009-06-22 19 views
14

Une API Java renvoie un java.util.Map<java.lang.String,java.lang.Boolean>;. Je voudrais mettre cela en un Map[String,Boolean]Comment convertir un fichier java.util.Map en Scala Map

imagine Nous avons donc:

var scalaMap : Map[String,Boolean] = Map.empty 
val javaMap = new JavaClass().map() // Returns java.util.Map<java.lang.String,java.lang.Boolean> 

Vous ne pouvez pas faire Map.empty ++ javaMap, parce que la méthode ++ ne sait pas sur les cartes Java. J'ai essayé:

scalaMap = Map.empty ++ new collection.jcl.MapWrapper[String,Boolean] { 
    override def underlying = javaMap 
} 

et:

scalaMap = Map.empty ++ new collection.jcl.MapWrapper[java.lang.String,java.lang.Boolean] { 
    override def underlying = javaMap 
    } 

Ces deux ne parviennent pas à compiler, en raison des génériques - java.lang.String n'est pas la même que celle d'une chaîne de scala.

Existe-t-il une bonne façon de procéder, à moins de copier manuellement la carte?

EDIT: Merci, toutes les bonnes réponses, j'ai beaucoup appris de tous. Cependant, j'ai fait une erreur en publiant un problème plus simple ici que celui que j'ai réellement. Donc, si vous me le permettez, je vais généraliser la question - Qu'est-ce que l'API retourne en fait est

java.util.Map<java.lang.String, java.util.Map<SomeJavaEnum,java.lang.String>> 

Et je dois déplacer ce à la carte [String, Carte [SomeJavaEnum, String]]

Il Cela ne semble probablement pas trop compliqué, mais il ajoute un niveau supplémentaire d'effacement de type, et la seule façon de le déplacer vers une carte Scala était de le copier en profondeur (en utilisant certaines des techniques suggérées ci-dessous). Quelqu'un a des allusions? J'ai en quelque sorte résolu mon problème en définissant une conversion implicite pour mes types exacts, donc au moins la laideur est cachée dans son propre trait, mais se sent encore un peu maladroite en profondeur en copiant le sort.

+0

J'aime bien la réponse Conversions que j'ai reçue du groupe d'utilisateurs scala. Juste besoin de vérifier si cela fonctionne ... Mais il est trop tard ici maintenant, donc sera de retour bientôt ... – George

Répondre

2

useJavaMap.scala

import test._ 
import java.lang.Boolean 
import java.util.{Map => JavaMap} 
import collection.jcl.MapWrapper 

object useJavaMap { 
    def main(args: Array[String]) { 
    var scalaMap : Map[String, Boolean] = Map.empty 
    scalaMap = toMap(test.testing()) 
    println(scalaMap) 
    } 

    def toMap[K, E](m: JavaMap[K, E]): Map[K, E] = { 
    Map.empty ++ new MapWrapper[K, E]() { 
     def underlying = m 
    } 
    } 
} 

test/test.java

package test; 

import java.util.*; 

public class test { 
    public static Map<String, Boolean> testing() { 
     Map<String, Boolean> x = new HashMap<String, Boolean>(); 
     x.put("Test",Boolean.FALSE); 
     return x; 
    } 
    private test() {} 
} 

Commandline

javac test\test.java 
scalac useJavaMap.scala 
scala useJavaMap 
> Map(Test -> false) 
+0

Ni ces deux œuvres, j'ai peur. Ce sont des classes génériques - Map [String, Boolean] n'est pas la même chose que Map [java.lang.String, java.lang.Boolean], vous obtenez donc: type mismatch; trouvé: java.lang.Object avec scala.collection.jcl.MapWrapper [String, Boolean] \t {...} requis: Map [String, Boolean] (en utilisant le premier exemple) – George

+0

a eu le temps de l'essayer. échantillon complet fourni – jitter

+0

Merci, 'Map.empty ++ JMapWrapper [K, V] (myJavaMap)' est ce que je veux! –

0

Je pense que j'ai une réponse partielle ...

Si vous convertissez la carte Java en une carte scala avec les types java. Vous pouvez ensuite mapper à une carte de scala des types de scala:

val javaMap = new java.util.TreeMap[java.lang.String, java.lang.Boolean] 
val temp = new collection.jcl.MapWrapper[java.lang.String,java.lang.Boolean] { 
    override def underlying = javaMap 
} 
val scalaMap = temp.map{ 
    case (k, v) => (k.asInstanceOf[String] -> v.asInstanceOf[Boolean]) 
} 

Le défaut de ce plan est que le type de scalaMap est Iterable [(java.lang.String, Boolean)] pas une carte. Je me sens si proche, quelqu'un de plus intelligent que moi peut-il réparer la dernière déclaration pour faire ce travail ?!

6

Une Scala String est un java.lang.Stringmais une Scala Booleann'est pas un java.lang.Boolean.Par conséquent, les travaux suivants:

import collection.jcl.Conversions._ 
import collection.mutable.{Map => MMap} 
import java.util.Collections._ 
import java.util.{Map => JMap} 

val jm: JMap[String, java.lang.Boolean] = singletonMap("HELLO", java.lang.Boolean.TRUE) 

val sm: MMap[String, java.lang.Boolean] = jm //COMPILES FINE 

Mais votre problème est toujours le problème avec la différence Boolean. Vous devrez « plier » la carte Java dans la scala un: essayez d'utiliser à nouveau le type Scala Boolean:

val sm: MMap[String, Boolean] = collection.mutable.Map.empty + ("WORLD" -> false) 
val mm = (sm /: jm) { (s, t2) => s + (t2._1 -> t2._2.booleanValue) } 

Ensuite mm est une carte scala contenant le contenu de la carte scala originale plus ce qui était dans la La carte Java

+0

En fait, votre réponse convertit en carte mutable, alors que l'auteur a demandé immuable. –

11

Au moins avec Scala 2.9.2, il existe un moyen plus simple avec les conversions de collections: importer "import collection.JavaConversions._" et utiliser "toMap".

Exemple:

// show with Java Map: 

scala> import java.util.{Map=>JMap} 
scala> val jenv: JMap[String,String] = System.getenv() 
jenv: java.util.Map[String,String] = {TERM=xterm, ANT_OPTS=-Xmx512m ...} 

scala> jenv.keySet() 
res1: java.util.Set[String] = [TERM, ANT_OPTS...] 

// Now with Scala Map: 

scala> import collection.JavaConversions._ 
scala> val env: Map[String,String] = System.getenv.toMap // <--- TADA <--- 
env: Map[String,String] = Map(ANT_OPTS -> -Xmx512m, TERM -> xterm ...) 

// Just to prove it's got Scala functionality: 

scala> env.filterKeys(_.indexOf("TERM")>=0) 
res6: scala.collection.immutable.Map[String,String] = Map(TERM -> xterm, 
    TERM_PROGRAM -> iTerm.app, ITERM_PROFILE -> Default) 

Il fonctionne très bien avec un java.util.map de chaîne à Boolean.