Модуль Jackson Scala, вложенные списки и карты - PullRequest
2 голосов
/ 09 января 2012

Я хочу преобразовать списки объектов 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)))

Ответы [ 4 ]

0 голосов
/ 04 января 2013

ОК, поэтому, используя более позднюю версию модуля 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)
0 голосов
/ 10 января 2012

Я не использовал Модуль Джексона Скала, но в Джерксоне поведение такое же, поэтому я рискну догадаться, что происходит.Когда REPL печатает:

myList -> [{test2=321323}, {test3=11122}])

, он сообщает вам, что есть кортеж, содержащий «myList» и java.util.ArrayList.ArrayList содержит два java.util.LinkedHashMaps.(Я объясняю это, потому что поначалу мне это было неочевидно, и мне пришлось потратить некоторое время на REPL, используя getClass и asInstanceOf, чтобы погрузиться в эту структуру.)

Я вполне уверен, что нетспособ получить модуль Jackson Scala или Jerkson вернуть десериализованный JSON с собственными коллекциями Scala.Вы можете импортировать 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 не обрабатывает десериализационные классы case в REPL.)

Я знаю васможет десериализовать объект с Джексоном, но в прошлый раз, когда я посмотрел, потребовалось еще несколько шагов.

Это правильный путь для ответа на ваш вопрос?

0 голосов
/ 10 января 2012

В конечном итоге я последовал совету Лейфа и написал этот код для решения проблемы

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
}
0 голосов
/ 09 января 2012

Если это не работает должным образом, пожалуйста, сообщите о проблеме с модулем Jackson Scala на [https://github.com/FasterXML/jackson-module-scala/issues].. Возможно, что есть проблемы с обработкой содержимого в режиме «нетипизированного» (т.е. не в бине, с использованием Lists, Maps)и т.д.) для какого модуля scala необходимо добавить специальную обработку.Основная проблема заключается в том, что коллекции Scala в целом не отображаются должным образом с коллекциями JDK.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...