1

circe を使用すると、ケース クラスで Json を簡単にデコードできます。

import io.circe._, io.circe.generic.auto._, io.circe.parser._, io.circe.syntax._


case class Bar(xs: List[String])


scala> decode[Bar]("{\"xs\":[\"a\",\"b\"]}")
res2: Either[io.circe.Error,Bar] = Right(Bar(List(a, b)))

scala> decode[Bar]("{\"xs\":[\"a\",\"b\"],\"addedField\":true}")
res3: Either[io.circe.Error,Bar] = Right(Bar(List(a, b)))

しかし、すべてのフィールドが使用され、結果にマップされているかどうかを確認する方法がわかります。

現在、一部の情報が失われているかどうかを確認する方法の 1 つは、結果を json に再変換し、json を比較することです (Json4 を使用)。

scala> val Diff(_,_,removed) = parse(input) diff parse(result.asJson.noSpaces)
removed: org.json4s.JsonAST.JValue = JObject(List((addedField,JBool(true))))

val noLoss = removed == JNothing

circe で直接それを行う方法はありますか?

4

2 に答える 2

2

ここでの主な問題は、フィールドがデコーダーによって消費されるかどうかを判断する明確な方法がないことです。
そのような消費の概念を定義しようとすると、case classes で期待どおりに動作します。

import shapeless._
import shapeless.labelled.FieldType 

trait FieldNames[T] {
  def names: Set[String]
}

object FieldNames {
  implicit val hNilNames = new FieldNames[HNil] {
    def names = Set.empty
  }

  implicit def hConsNames[S <: Symbol, A, T <: HNil]
  (implicit witness: Witness.Aux[S], tail: FieldNames[T]) = new FieldNames[FieldType[S, A] :: T] {
    lazy val names = tail.names + witness.value.name
  }

  implicit def ccNames[CC, Out <: HList]
  (implicit lgen: LabelledGeneric.Aux[CC, Out], genNames: Lazy[FieldNames[Out]]) = new FieldNames[CC] {
    lazy val names = genNames.value.names
  }
}

これで、いくつかの剰余キャッチャーラッパーと対応するデコーダーを表すことができます。

case class Tidy[X](value: X, remains: Option[JsonObject] = None)

object Tidy {
  implicit def tidyDecoder[X](implicit decoder: Decoder[X], fields: FieldNames[X]) =
    Decoder.instance[Tidy[X]] { cur =>
      decoder(cur) map { x =>
        Tidy(x, cur.focus.asObject.flatMap { obj =>
          Some(obj.filterKeys(!fields.names.contains(_))).filter(_.nonEmpty)
        })
      }
    }
}

これがあれば、残りのフィールドを抽出してみることができます:

val json1 =
  """{
    "xs" : ["a", "b"]
    }
  """

val json2 =
  """{
    "xs" : ["a", "b"],
    "addedField": true
    }
  """

decode[Tidy[Bar]](json1) // Right(Tidy(Bar(List(a, b)),None))
decode[Tidy[Bar]](json2) // Right(Tidy(Bar(List(a, b)),Some(object[addedField -> true])))
于 2017-01-09T15:04:29.677 に答える
0

簡単な組み込みの方法はありません。

このトピックの circe メインメンテナーと貢献者との間の議論については、この問題を参照できます。

免責事項: 決定的な結論はありません^^

于 2017-01-09T14:09:08.613 に答える