Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to convert from from java.util.Map to a Scala Map

A Java API returns a java.util.Map<java.lang.String,java.lang.Boolean>;. I would like to put that into a Map[String,Boolean]

So imagine we have:

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

You can't do Map.empty ++ javaMap, because the ++ method does not know about Java maps. I tried:

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

and:

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

These both fail to compile, because of the generics - java.lang.String is not the same as a scala String.

Is there a good way of doing this, short of copying the map manually?

EDIT: Thanks, all good answers, I learned a lot from all of them. However, I made a mistake by posting a simpler problem here than the one I actually have. So, if you allow me, I'll generalise the question - What the API actually returns is

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

And I need to move this to Map[String, Map[SomeJavaEnum,String]]

It probably does not seem like too much of a complication, but it adds an extra level of type erasure, and the only way I found of moving this to a Scala map was deep-copying it (using some of the techniques you suggested below). Anyone any hints? I kind of solved my problem by defining an implicit conversion for my exact types, so at least the ugliness is hidden in its own trait, but still feels a bit clumsy deep copying the lot.

like image 852
George Avatar asked Jun 22 '09 15:06

George


People also ask

How can we convert mutable Map to immutable Scala?

If you just want a mutable HashMap , you can just use x. toMap in 2.8 or collection. immutable. Map(x.

How do you make a Map in Scala?

Map class explicitly. If you want to use both mutable and immutable Maps in the same, then you can continue to refer to the immutable Map as Map but you can refer to the mutable set as mutable. Map. While defining empty map, the type annotation is necessary as the system needs to assign a concrete type to variable.

What is difference between Map and HashMap in Scala?

Scala map is a collection of key/value pairs. Any value can be retrieved based on its key. Keys are unique in the Map, but values need not be unique. HashMap implements immutable map and uses hash table to implement the same.

How do I convert a Map to a list of objects?

You can convert it into two list objects one which contains key values and the one which contains map values separately. Create a Map object. Create an ArrayList of integer type to hold the keys of the map. In its constructor call the method keySet() of the Map class.


1 Answers

At least with Scala 2.9.2 there's an easier way with the collections conversions: import "import collection.JavaConversions._" and use "toMap".

Example:

// 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)

It works fine with a java.util.map of String to Boolean.

like image 152
Andrew E Avatar answered Sep 21 '22 15:09

Andrew E