我希望转换json对象的列表,这些对象本身可能包含Json对象或Json对象列表,并且希望结果是Scala Maps或Lists,但是,我只能获得顶级对象转换为地图或列表。 有一种简单的方法可以做到这一点吗?
例如在REPL中
objectMapper.readValue("{\"test\":\"113123\",\"myList\":[{\"test2\":\"321323\"},{\"test3\":\"11122\"}]}", classOf[Map[String,Any]])
将返回
res: Map[String,Any] = Map(test -> 113123, myList -> [{test2=321323}, {test3=11122}])
我想要的地方
res: Map[String,Any] = Map(test -> 113123, myList -> List(Map(test2 -> 321323), Map(test3 -> 111222)))
答案 0 :(得分:0)
如果这不能按预期工作,请在[https://github.com/FasterXML/jackson-module-scala/issues]上针对Jackson Scala模块提出问题。在“无类型”模式(即非bean,使用列表,地图等)中处理内容可能存在问题,scala模块需要为其添加特殊处理。潜在的挑战是Scala集合通常不会与JDK集合完全映射。
答案 1 :(得分:0)
我没有使用过Jackson Scala模块,但Jerkson的行为是一样的,所以我会猜测发生了什么。当REPL正在打印时:
myList -> [{test2=321323}, {test3=11122}])
它告诉你有一个包含“myList”和java.util.ArrayList的元组。 ArrayList包含两个java.util.LinkedHashMaps。 (我解释一下,因为起初我并不明白,我不得不花费一些时间在REPL上使用getClass和asInstanceOf来深入研究这个结构。)
我很确定没有办法让Jackson Scala Module或Jerkson返回带有原生Scala集合的反序列化JSON。您可以导入scala.collect.JavaConversions以使这些值看起来更像Scala。即使你这样做,你仍然需要施展。例如:
import com.codahale.jerkson.Json._
import collection.JavaConversions._
import java.util._
res("myList").asInstanceOf[ArrayList[LinkedHashMap[String,String]]](0)("test2")
>> String = 321323
如果你不想摆弄所有的转换,我认为你需要做的是定义一个反序列化的类。例如,使用Jerkson:
import com.codahale.jerkson.Json._
import collection.immutable.{Map,List}
case class MyClass(test: Integer, myList: List[Map[String,String]])
object M {
def main(args: Array[String]) {
val t =parse[MyClass]("""{"test":"113123","myList":[{"test2":"321323"},{"test3":"11122"}]}""")
println(t.myList(0)("test2"))
}
}
(我之所以把它写成一个完整的程序,是因为Jerkson不会在REPL中处理反序列化的案例类。)
我知道你可以用Jackson反序列化一个物体,但是上次我看了它又花了几步。
这是否正确回答您的问题?
答案 2 :(得分:0)
最终我遵循了Leif的建议并编写了这段代码来解决问题
private def mapToMap(map:java.util.Map[String,Any]) : Map[String,Any] = {
val mb = new MapBuilder[String, Any, HashMap[String, String]](new HashMap[String, String])
val iterator = map.keySet().iterator
while (iterator.hasNext) {
val key = iterator.next
mb += (key -> checkValue(map.get(key)))
}
mb.result
}
private def arrayToList(array:java.util.ArrayList[Any]) : List[Any] = {
val lb = new ListBuffer[Any]()
val iterator = array.iterator
while(iterator.hasNext) lb += checkValue(iterator.next)
lb.result
}
private def checkValue(value:Any) : Any = value match {
case l: java.util.ArrayList[Any] => arrayToList(l)
case m: java.util.Map[String,Any] => mapToMap(m)
case _ => value
}
答案 3 :(得分:0)
好的,所以使用更高版本的scala jackson模块我创建了这个类
private class NestedTypeObjectDeserializer extends JacksonUntypedObjectDeserializer {
override def mapArray(jp: JsonParser, ctxt: DeserializationContext): AnyRef =
super.mapArray(jp, ctxt).asInstanceOf[ArrayList[AnyRef]].asScala.toList
override def mapObject(jp: JsonParser, ctxt: DeserializationContext): AnyRef =
super.mapObject(jp, ctxt).asInstanceOf[LinkedHashMap[String, AnyRef]].asScala.toMap
}
private object NestedTypeObjectDeserializerResolver extends Deserializers.Base {
lazy val OBJECT = classOf[AnyRef]
override def findBeanDeserializer(javaType: JavaType,
config: DeserializationConfig,
beanDesc: BeanDescription) =
if (!OBJECT.equals(javaType.getRawClass)) null
else new NestedTypeObjectDeserializer
}
trait NestedTypeObjectDeserializerModule extends JacksonModule {
this += (_ addDeserializers NestedTypeObjectDeserializerResolver)
}
您可以将其应用于对象映射器
val objectMapper = new ObjectMapper()
val module = new OptionModule with MapModule with SeqModule with IteratorModule with NestedTypeObjectDeserializerModule {}
objectMapper.registerModule(module)