Разобрать объекты Json в case-классы в Scala?

У меня есть массив объектов Json. Все эти объекты следуют одной из двух структур: Первая, как эта:

{
            "uuid": "321,
            "uuidType": "series",
            "title": "a movie",
            "segments": [
                "movie"
            ],
            "seriesIds": [
                "123"
            ]
        }

А второй вот так:

 {
            "uuid": "1234",
            "uuidType": "programme",
            "title": "programme title",
            "type": "movie",
            "segments": [
                "movies"
            ],
            "programmeIds": [
                "321"
            ]
        }

Тем не менее, я хочу разобрать эти объекты в один и тот же класс case следующим образом:

case class SearchResult(uuid: String, uuidType: String, title: String, segments: List[String], ids: List[String])

Таким образом, со вторым типом объекта ключ и значение типа будут игнорироваться, и оба seriesIds из первого объекта и programmeIds из второго объекта будут входить в часть id класса case. Однако я понятия не имею, как это сделать! Я использую Circe для декодирования / кодирования JSON.

2 ответа

Решение

Вы можете разместить собственный декодер в сопутствующем объекте SearchResult.

Скала 2.12
Цирцея 0.9.3

import io.circe._
import io.circe.parser._

object Main extends App {

  val jsonA =
    """{
         "uuid": "321",
         "uuidType": "series",
         "title": "a movie",
         "segments": [
            "movie"
         ],
         "seriesIds": [
            "123"
         ]
       }"""

  val jsonB =
    """{
        "uuid": "1234",
        "uuidType": "programme",
        "title": "programme title",
        "type": "movie",
        "segments": [
          "movies"
        ],
        "programmeIds": [
          "321"
        ]
       }"""

  case class SearchResult(uuid: String, uuidType: String, title: String, segments: List[String], ids: List[String])

   object SearchResult {

    implicit val decoder: Decoder[SearchResult] = Decoder.instance { h =>

    for {
      uuid <- h.get[String]("uuid")
      uuidType <- h.get[String]("uuidType")
      title <- h.get[String]("title")
      segments <- h.get[List[String]]("segments")
      ids <- {
        h.getOrElse[List[String]]("seriesIds")(h.get[List[String]]("programmeIds").getOrElse(Nil))
      }
    } yield SearchResult(uuid, uuidType, title, segments, ids)

   }

  }

  val obj1 = decode[SearchResult](jsonA)
  println(obj1)

  val obj2 = decode[SearchResult](jsonB)
  println(obj2)

  }

Вы можете написать собственный код в circe, чтобы получить желаемый эффект, но мне кажется, было бы проще использовать автоматическую десериализацию circe и определить свой класс case как

case class SearchResult(uuid: String, uuidType: String, title: String, segments: List[String], programmeIds: Option[List[String]], seriesIds: Option[List[String]])

и преобразовать это в идентификаторы, используя простой код Scala

Другие вопросы по тегам