Разобрать массив JSON как класс case с помощью Circe

Давайте использовать этот пример JSON:

{
  "bids": [
    [16182.06, 0.02994158],
    [16179.56, 0.01902097],
    [16178.05, 0.06538498]
  ],
  "asks": [
    [16191.92, 0.03597287],
    [16193.33, 0.0839688],
    [16194.95, 0.0857127]
  ]
}

Ничего особенного, на самом деле, это можно было бы просто разобрать на класс case:

@JsonCodec case class OrderBook(bids: Seq[Seq[Double]], asks: Seq[Seq[Double]])

Это прекрасно работает ...


Проблема

Я действительно знаю, что каждый массив будет иметь размер 2 и

  • первый элемент -> это "ставка"
  • второй элемент -> это "сумма"

Я хочу исправить это с помощью Circe и разобрать его на структуру класса, например:

@JsonCodec case class OrderBook(bids: Seq[Elems], asks: Seq[Elems])

case class Elems(rate: Double, amount: Double)

Я пробовал написать свой кодировщик и декодер:

object Elems {
  implicit val encodeElems: Encoder[Elems] = (a: Elems) =>
    Json.arr(
      Json.fromDoubleOrNull(a.rate), Json.fromDoubleOrNull(a.amount)
    )

  implicit val decodeElems: Decoder[Elems] = (c: HCursor) =>
    for {
      f <- c.downArray.as[Seq[Double]]
    } yield {
      Elems(f(0), f(1))
    }
}

Но у меня всегда выходит с ошибкой:

Caused by: DecodingFailure(CanBuildFrom for A, List(DownArray, DownArray, DownField(bids)))

Почему? Что я делаю неправильно?


person Atais    schedule 09.09.2017    source источник


Ответы (1)


downArray перемещает фокус со списка на его первый элемент. Когда используется Elems.decodeElems, c = <[1, 2]>, поэтому c.downArray = <1>, а затем вы пробуете <1>.as[Seq[Double]], который взрывается. Во-вторых, вы должны использовать as[(Double, Double)], который будет декодировать список точно так же, как вы, но также убедитесь, что он состоит из двух элементов.

implicit val decodeElems: Decoder[Elems] = (c: HCursor) =>
  for {
    f <- c.as[(Double, Double)]
  } yield Elems(f._1, f._2)
person HTNW    schedule 09.09.2017