2015-12-23 53 views
4

我目前正在處理期望Java類型的AWS Java SDK。將嵌套的Scala類型轉換爲Java類型

我一直在使用JavaConverters來明確地將類型如地圖和列表轉換爲java。我遇到了越來越複雜的類型,並發現自己不得不深入到變得笨拙的列表中。

我目前的問題是我有一個Map[String, List[String]]將整個對象轉換爲java很簡單,但是當模式與地圖中的列表匹配時,我被類型擦除命中。

val t = m.map{ 
    case (k, v: List[String]) => k -> v //type erasure so unreachable 
} 

我在Scala中發現了一個很好的解釋,它是我想實現的一個優雅的解決方案。 Scala: What is a TypeTag and how do I use it?

我只是不確定我是如何實現這個到我的模式匹配。

,我實現了看起來像這樣

def isNestedMap[A : TypeTag](xs: A): Boolean = typeOf[A] match { 
    case t if t =:= typeOf[Map[String, List[String]]] => true 
    case t => false 
} 

和新情況的方法case (k, v) if isNestedMap(v) => k -> "beans"但這始終返回false我的方法是看到類型爲Any

任何想法如何克服?或者更好的方式遞歸轉換深層列表或地圖到他們的Java等值?

謝謝大家。

編輯:地圖實際上是一個類型的Map[String, Any]所以我需要知道的Any類型之前,我可以把它轉換成Java

回答

1

編輯:地圖實際上是一個類型的地圖的[字符串,任何]所以我需要我以前知道的任何類型可以將其轉換成Java

TypeTag S通過編譯器根據靜態類型插入,所以當你調用isNestedMap(v),它會看到v: Any並插入isNestedMap[Any](v)(typeTag[Any])

或者更好的方式遞歸轉換深層列表或地圖到他們的java等價物?

喜歡的東西

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 
} 

你可以把它分成不同的功能listDeepAsJava等,以獲得更好的類型簽名每個:

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 
... 
+0

這幾乎就是我正在尋找的解決方案,唯一的問題是結果是一種'Any',我不得不用'.asInstanceOf [java.util .List [java.util.Map [String,Any]]]任何想法我可以隱式地做到這一點?感覺就像你提到的分裂方法,會允許這個,但是當試圖這樣做時,它抱怨類型不匹配時該方法的簽名是'listDeepAsJava(x:List [Any]):java.util.List [Any]' – user3750194

+0

是的,這就是爲什麼我建議拆分方法。在裏面使用'深AsJava':我已經更新了答案以澄清。當然,它仍然只有'java.util.List [Any]'。要獲得'java.util.List [java.util.Map [...]]'會變得更加複雜。 –

+0

非常感謝您的幫助。這是我尋找的雄辯的解決方案! – user3750194

2

我不認爲你的問題確實是關係到擦除或甚至需要使用類型標籤。下面是在REPL展示的一種方式快速會話,使轉換:

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]} 
+0

我可能不是在我原來的答覆不夠清楚,但地圖類型實際上是'地圖[字符串,任何]'所以'映射:( – user3750194

+0

所以類型的標籤,當.asJava'不可用能」 t可能對你有幫助 – pedrofurla

0

嘗試用Array而不是List

val m = Map[String, Array[String]]() 
val t = m.map{ 
    case (k, v: Array[String]) => k -> v //no type erasure 
}