Reputation: 407
I'm currently dealing with the AWS Java SDK, which expects Java types.
I've been using JavaConverters
to explicitly converts types like maps and lists to java. I've been running into more and more complex types and found myself having to map deep into lists which is becoming unwieldy.
My current issue is I have a Map[String, List[String]]
converting the overall object to java is simple but I'm being hit by type erasure when pattern matching the list in the map.
val t = m.map{
case (k, v: List[String]) => k -> v //type erasure so unreachable
}
I found a great explanation of Type Tags in Scala which is an elegant solution I'd like to implement. Scala: What is a TypeTag and how do I use it?
I'm just unsure how I'm implement this into my pattern match.
I've implemented a method that looks like so
def isNestedMap[A : TypeTag](xs: A): Boolean = typeOf[A] match {
case t if t =:= typeOf[Map[String, List[String]]] => true
case t => false
}
And a new case case (k, v) if isNestedMap(v) => k -> "beans"
but this always return false as my method is seeing types as an Any
.
Any ideas how to surmount this? Or better yet a way of recursively convert deep lists or maps to their java equivalents?
Thanks all.
EDIT: The Map is actually a type of Map[String, Any]
so I need to know the type of Any
before I can convert it to Java
Upvotes: 4
Views: 713
Reputation: 170899
EDIT: The Map is actually a type of Map[String, Any] so I need to know the type of Any before I can convert it to Java
TypeTag
s are inserted by the compiler according to the static type, so when you call isNestedMap(v)
, it'll see v: Any
and insert isNestedMap[Any](v)(typeTag[Any])
.
Or better yet a way of recursively convert deep lists or maps to their java equivalents?
Something like
def deepAsJava(x: Any): Any = x match {
case l: List[_] => l.map(deepAsJava).asJava
case m: Map[_, _] => m.map { case (k, v) => (k, deepAsJava(v)) }.asJava
case ... // other collections you want to support
case x => x
}
You can split it into separate functions for listDeepAsJava
, etc. to get better type signatures for each:
def deepAsJava(x: Any): Any = x match {
case l: List[_] => listDeepAsJava(l)
case m: Map[_, _] => mapDeepAsJava(m)
case ... // other collections you want to support
case x => x
}
def listDeepAsJava(x: List[Any]): java.util.List[Any] = l.map(deepAsJava).asJava
...
Upvotes: 1
Reputation: 18034
Try with Array
instead of List
.
val m = Map[String, Array[String]]()
val t = m.map{
case (k, v: Array[String]) => k -> v //no type erasure
}
Upvotes: 0
Reputation: 12783
I don't think you problem is really related to erasure or even needs to make use of type tags. Here is quick session on the REPL demonstrating one way to make the conversions:
scala> import collection.JavaConverters._
import collection.JavaConverters._
scala> List(1,2,3).asJava
res0: java.util.List[Int] = [1, 2, 3]
scala> Map(1 -> List(1),2 -> List(2))
res1: scala.collection.immutable.Map[Int,List[Int]] = Map(1 -> List(1), 2 -> List(2))
scala> res1.asJava
res2: java.util.Map[Int,List[Int]] = {1=List(1), 2=List(2)}
scala> res1.map{ case (l,r) => l -> r.asJava}.asJava
res3: java.util.Map[Int,java.util.List[Int]] = {1=[1], 2=[2]}
scala> res1.mapValues(_.asJava).asJava
res5: java.util.Map[Int,java.util.List[Int]] = {1=[1], 2=[2]}
Upvotes: 2