解析 Circe 中的原始类型
Parsing primitive types in Circe
当字段可以具有不同的原始值类型时,我在 json 解析时遇到问题。例如,我可以得到 json:
{
"name" : "john",
"age" : 31
}
也可以是这种形式:
{
"name" : "john",
"age" : "thirty one"
}
或者这样:
{
"name" : "john",
"age" : 31.0
}
我希望能够将字段 age
解析为以下 ADT 实例:
sealed trait PrimitiveWrapper
case class IntWrapper(v: Int) extends PrimitiveWrapper
case class StringWrapper(v: String) extends PrimitiveWrapper
case class FloatWrapper(v: Float) extends PrimitiveWrapper
所以最后我可以得到这样的东西:
case class Person(name: String, age: PrimitiveWrapper)
我该怎么做?我找到了这个主题:
但在该解决方案中,我们解析的不是原始字段。
你可以这样做:
import cats.syntax.functor._
import io.circe.Decoder, io.circe.generic.auto._
sealed trait PrimitiveWrapper
case class IntWrapper(v: Int) extends PrimitiveWrapper
case class StringWrapper(v: String) extends PrimitiveWrapper
case class FloatWrapper(v: Float) extends PrimitiveWrapper
case class Person(name: String, age: PrimitiveWrapper)
object GenericDerivation {
implicit val decodePrimitiveWrapper: Decoder[PrimitiveWrapper] =
List[Decoder[PrimitiveWrapper]](
Decoder.decodeInt.map(IntWrapper).widen,
Decoder.decodeString.map(StringWrapper).widen,
Decoder.decodeFloat.map(FloatWrapper).widen
).reduceLeft(_ or _)
def main(args: Array[String]): Unit = {
import io.circe.parser.decode
println(decode[Person]("""{"name" : "john", "age" : 31 }"""))
println(decode[Person]("""{"name" : "john", "age" : "thirty one" }"""))
println(decode[Person]("""{"name" : "john", "age" : 31.3 }"""))
// Prints
// Right(Person(john,IntWrapper(31)))
// Right(Person(john,StringWrapper(thirty one)))
// Right(Person(john,FloatWrapper(31.3)))
}
}
注:下面的get parse using an IntWrapper
println(decode[Person]("""{"name" : "john", "age" : 31.0 }"""))
更新: 正如@Travis 指出的那样,decodePrimitiveWrapper
可以这样写:
implicit val decodePrimitiveWrapper: Decoder[PrimitiveWrapper] =
Decoder.decodeInt.map(IntWrapper).widen[PrimitiveWrapper] or
Decoder.decodeString.map(StringWrapper).widen[PrimitiveWrapper] or
Decoder.decodeFloat.map(FloatWrapper).widen[PrimitiveWrapper]
当字段可以具有不同的原始值类型时,我在 json 解析时遇到问题。例如,我可以得到 json:
{
"name" : "john",
"age" : 31
}
也可以是这种形式:
{
"name" : "john",
"age" : "thirty one"
}
或者这样:
{
"name" : "john",
"age" : 31.0
}
我希望能够将字段 age
解析为以下 ADT 实例:
sealed trait PrimitiveWrapper
case class IntWrapper(v: Int) extends PrimitiveWrapper
case class StringWrapper(v: String) extends PrimitiveWrapper
case class FloatWrapper(v: Float) extends PrimitiveWrapper
所以最后我可以得到这样的东西:
case class Person(name: String, age: PrimitiveWrapper)
我该怎么做?我找到了这个主题:
但在该解决方案中,我们解析的不是原始字段。
你可以这样做:
import cats.syntax.functor._
import io.circe.Decoder, io.circe.generic.auto._
sealed trait PrimitiveWrapper
case class IntWrapper(v: Int) extends PrimitiveWrapper
case class StringWrapper(v: String) extends PrimitiveWrapper
case class FloatWrapper(v: Float) extends PrimitiveWrapper
case class Person(name: String, age: PrimitiveWrapper)
object GenericDerivation {
implicit val decodePrimitiveWrapper: Decoder[PrimitiveWrapper] =
List[Decoder[PrimitiveWrapper]](
Decoder.decodeInt.map(IntWrapper).widen,
Decoder.decodeString.map(StringWrapper).widen,
Decoder.decodeFloat.map(FloatWrapper).widen
).reduceLeft(_ or _)
def main(args: Array[String]): Unit = {
import io.circe.parser.decode
println(decode[Person]("""{"name" : "john", "age" : 31 }"""))
println(decode[Person]("""{"name" : "john", "age" : "thirty one" }"""))
println(decode[Person]("""{"name" : "john", "age" : 31.3 }"""))
// Prints
// Right(Person(john,IntWrapper(31)))
// Right(Person(john,StringWrapper(thirty one)))
// Right(Person(john,FloatWrapper(31.3)))
}
}
注:下面的get parse using an IntWrapper
println(decode[Person]("""{"name" : "john", "age" : 31.0 }"""))
更新: 正如@Travis 指出的那样,decodePrimitiveWrapper
可以这样写:
implicit val decodePrimitiveWrapper: Decoder[PrimitiveWrapper] =
Decoder.decodeInt.map(IntWrapper).widen[PrimitiveWrapper] or
Decoder.decodeString.map(StringWrapper).widen[PrimitiveWrapper] or
Decoder.decodeFloat.map(FloatWrapper).widen[PrimitiveWrapper]