Извлечение вложенного сериализованного json с json4s в case-классы в Scala - PullRequest
0 голосов
/ 16 февраля 2019

Я пытаюсь проанализировать следующий Json с json4s в Scala, но не могу из-за вложенной структуры:

[
 {
    "body":"8",
    "start":29,
    "value":{
        "value":8,
        "type":"value"
        },
    "end":30,
    "dim":"number",
    "latent":false
 },
 {
    "body":"2",
    "start":42,
    "value":{
        "value":2,
        "type":"value"
        },
    "end":43,
    "dim":"number",
    "latent":false
 }
]

С помощью следующего кода я могу извлечь только первый класс дела, новложенные классы не извлекаются:

println(stdout)
val obs = parse(stdout.toString())
val obs2 = parse(stdout.toString()).extract[DucklingList]
println(obs2.list)

Вот вывод вышеупомянутого:

[0m[[0minfo[0m] [0m[{"body":"8","start":29,"value":{"value":8,"type":"value"},"end":30,"dim":"number","latent":false},{"body":"2","start":42,"value":{"value":2,"type":"value"},"end":43,"dim":"number","latent":false}][0m
[0m[[0minfo[0m] [0mList(JObject(List((body,JString(8)), (start,JInt(29)), (value,JObject(List((value,JInt(8)), (type,JString(value))))), (end,JInt(30)), (dim,JString(number)), (latent,JBool(false)))), JObject(List((body,JString(2)), (start,JInt(42)), (value,JObject(List((value,JInt(2)), (type,JString(value))))), (end,JInt(43)), (dim,JString(number)), (latent,JBool(false)))))[0m
[0m[[0minfo[0m] [0mJObject(List((value,JInt(8)), (type,JString(value))))[0m
[0m[[0minfo[0m] [0mDucklingList(List(JObject(List((body,JString(8)), (start,JInt(29)), (value,JObject(List((value,JInt(8)), (type,JString(value))))), (end,JInt(30)), (dim,JString(number)), (latent,JBool(false)))), JObject(List((body,JString(2)), (start,JInt(42)), (value,JObject(List((value,JInt(2)), (type,JString(value))))), (end,JInt(43)), (dim,JString(number)), (latent,JBool(false))))))[0m

Я попытался извлечь его, используя метод извлечения json4s, с перечислением классов case и сериализаторов.ниже.

case class DucklingValue(

    value: Int,
    typ: String
  )

  case class DucklingEntity(
    body: String,
    start: Int,
    end: Int,
    value: List[JField],
    dim: String,
    latent: Boolean
  )

  case class DucklingList(
    list: List[JValue]
  )

class DucklingEntitySerializer extends CustomSerializer[DucklingEntity](format => (
  {
    case JObject(
      JField("body", JString(body))
      :: JField("start", JInt(start))
      :: JField("end", JInt(end))
      :: JField("value", JObject(value))
      :: JField("dim", JString(dim))
      :: JField("latent", JBool(latent))
      :: Nil
    ) => DucklingEntity(body, start.toInt, end.toInt, value, dim, latent)
  },
  {
    case duckling_entity: DucklingEntity =>
      JObject(
        JField("body", JString(duckling_entity.body))
        :: JField("start", JInt(duckling_entity.start))
        :: JField("end", JInt(duckling_entity.end))
        :: JField("value", JObject(duckling_entity.value))
        :: JField("dim", JString(duckling_entity.dim))
        :: JField("latent", JBool(duckling_entity.latent))
        :: Nil
      )
  }
))

class DucklingValueSerializer extends CustomSerializer[DucklingValue](format => (
  {
    case JObject(
      JField("value", JInt(value))
      :: JField("type", JString(typ))
      :: Nil
    ) => DucklingValue(value.toInt, typ)
  },
  {
    case duckling_value: DucklingValue =>
      JObject(
        JField("value", JInt(duckling_value.value))
        :: JField("type", JString(duckling_value.typ))
        :: Nil
      )
  }
))


class DucklingListSerializer extends CustomSerializer[DucklingList](format => (
  {
    case JArray(list) => DucklingList(list)
  },
  {
    case duckling_list: DucklingList =>
      JArray(duckling_list.list)
  }
))

Как я могу получить вложенный сериализованный класс дел DucklingEntity, также извлекаемый из DucklingList?

1 Ответ

0 голосов
/ 16 февраля 2019

json4s будет рекурсивно анализировать вложенные объекты, поэтому вам не нужен специальный сериализатор.

Проблема в том, что вы поместили JSON типы (JValue и JField) в десериализованные классыкогда вы должны просто поставить соответствующие классы case.Вот измененные версии ваших классов, которые должны анализироваться без какого-либо пользовательского сериализатора:

case class DucklingValue(
  value: Int,
  typ: String
)

case class DucklingEntity(
  body: String,
  start: Int,
  end: Int,
  value: DucklingValue,
  dim: String,
  latent: Boolean
)

case class DucklingList(
  list: List[DucklingEntity]
)

Также обратите внимание, что ваши десериализаторы являются ограничительными, поскольку они требуют, чтобы поля приходили в указанном вами определенном порядке.Лучше извлечь отдельные поля, например:

case obj: JObject =>
  DucklingValue(
    (obj \ "value").Extract[Int],
    (obj \ "type").Extract[String]
  )

Это также позволяет полям располагаться в любом порядке.Использование этого подхода также позволяет вам работать с необязательными полями и т. Д., Что не может сделать простое выражение match.

...