简体   繁体   English

是否可以在Circe中通过解码来警告未使用的值?

[英]Is the a way to warn about unused values with decoding in Circe ?

Using circe, it's is easy to decode Json in case classes : 使用circe,很容易在case类中解码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)))

But I can see a way to check if all the fields have been used and mapped in the result. 但是我可以看到一种检查所有字段是否都已使用并映射到结果中的方法。

Currently, one the way to check if some information as been lost is the retransform the result in json and diff the jsons (with Json4) 当前,检查某些信息是否丢失的一种方法是在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

Is there a way to that directly in circe ? 有没有办法直接绕开?

Main problem here, that there is not clear way to determine whether field is consumed by your decoder. 这里的主要问题是,没有明确的方法来确定解码器是否占用了字段。
If we'll try to define some notion of such consumption, working as expected for case class es: 如果我们尝试定义这种消耗的一些概念,则按case class es的预期进行工作:

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
  }
}

we can now represent some remainder catcher wrapper and corresponding decoder: 我们现在可以表示一些余数捕获器包装器和相应的解码器:

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)
        })
      }
    }
}

having this you can try to extract remaning fields: 有了这个,您可以尝试提取剩余字段:

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])))

There's no simple built-in way. 没有简单的内置方法。

You can refer to this issue for a discussion between circe main maintainer and a contributor in this topic. 您可以参考此问题 ,以使主要维护者与该主题的撰稿人之间进行讨论。

Disclaimer : there's no definitive conclusion ^^ 免责声明:没有明确的结论^^

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM