将嵌套对象编码为字符串
Encode nested object as a string
给定以下情况类:
case class Mailbox(value: String)
case class Group(objectType: String, mailbox: Mailbox)
我正在尝试找到一种方法来编码组对象,如下所示,其中 mailbox
被编码为字符串值,而不是对象:
{
"objectType" : "Group",
"mailbox" : "mailto:info@example.com"
}
通过自动推导,encoding/decoding 都成功了,但我最终得到的结果如下所示:
{
"objectType" : "Group",
"mailbox" : {
"value" : "mailto:info@example.com"
}
}
我可以通过添加如下自定义编码器来实现我想要的结果:
object Mailbox {
implicit val encoder: Encoder[Mailbox] = (m: Mailbox) => Json.fromString(m.value)
implicit val decoder: Decoder[Mailbox] = deriveDecoder[Mailbox]
}
但是,解码失败并显示以下内容:
DecodingFailure(Attempt to decode value on failed cursor, List(DownField(value), DownField(mailbox)))
我也试图通过为邮箱编写自定义解码器来解决这个问题,但得到了相同的结果。任何有关处理这种情况的正确方法的指导将不胜感激。
完整代码如下:
case class Mailbox(value: String)
object Mailbox {
implicit val encoder: Encoder[Mailbox] = (m: Mailbox) => Json.fromString(m.value)
implicit val decoder: Decoder[Mailbox] = deriveDecoder[Mailbox]
}
case class Group(objectType: String, mailbox: Mailbox)
object Sandbox {
def main(args: Array[String]): Unit = {
val group: Group = Group("Group", Mailbox("mailto:info@example.com"))
val json: String = group.asJson.spaces2
println(json)
parser.decode[Group](json) match {
case Right(group) => println(group)
case Left(err) => println(err)
}
}
}
请注意,这是派生示例,仅用于演示我的问题。
您可以使用 map
/ contramap
来将您的类型映射到 String 并返回:
object Mailbox {
implicit val encoder: Encoder[Mailbox] = Encoder.encodeString.contramap[Mailbox](_.value)
implicit val decoder: Decoder[Mailbox] = Decoder.decodeString.map[Mailbox](Mailbox.apply)
}
几乎完全描述这种情况的文档位于 Custom encoders/decoders
作为创建自定义 encoders/decoders 的替代方法,您还可以使用 circe extras 中的 deriveUnwrappedEncoder/deriveUnwrappedDecoder
。
只需在你的代码中添加以下导入即可 buid.sbt
:
libraryDependencies += "io.circe" %% "circe-generic-extras" % "xxx"
然后你将能够做到:
import io.circe.generic.extras.semiauto._
implicit val encoder: Encoder[Mailbox] = deriveUnwrappedEncoder
implicit val decoder: Decoder[Mailbox] = deriveUnwrappedDecoder
给定以下情况类:
case class Mailbox(value: String)
case class Group(objectType: String, mailbox: Mailbox)
我正在尝试找到一种方法来编码组对象,如下所示,其中 mailbox
被编码为字符串值,而不是对象:
{
"objectType" : "Group",
"mailbox" : "mailto:info@example.com"
}
通过自动推导,encoding/decoding 都成功了,但我最终得到的结果如下所示:
{
"objectType" : "Group",
"mailbox" : {
"value" : "mailto:info@example.com"
}
}
我可以通过添加如下自定义编码器来实现我想要的结果:
object Mailbox {
implicit val encoder: Encoder[Mailbox] = (m: Mailbox) => Json.fromString(m.value)
implicit val decoder: Decoder[Mailbox] = deriveDecoder[Mailbox]
}
但是,解码失败并显示以下内容:
DecodingFailure(Attempt to decode value on failed cursor, List(DownField(value), DownField(mailbox)))
我也试图通过为邮箱编写自定义解码器来解决这个问题,但得到了相同的结果。任何有关处理这种情况的正确方法的指导将不胜感激。
完整代码如下:
case class Mailbox(value: String)
object Mailbox {
implicit val encoder: Encoder[Mailbox] = (m: Mailbox) => Json.fromString(m.value)
implicit val decoder: Decoder[Mailbox] = deriveDecoder[Mailbox]
}
case class Group(objectType: String, mailbox: Mailbox)
object Sandbox {
def main(args: Array[String]): Unit = {
val group: Group = Group("Group", Mailbox("mailto:info@example.com"))
val json: String = group.asJson.spaces2
println(json)
parser.decode[Group](json) match {
case Right(group) => println(group)
case Left(err) => println(err)
}
}
}
请注意,这是派生示例,仅用于演示我的问题。
您可以使用 map
/ contramap
来将您的类型映射到 String 并返回:
object Mailbox {
implicit val encoder: Encoder[Mailbox] = Encoder.encodeString.contramap[Mailbox](_.value)
implicit val decoder: Decoder[Mailbox] = Decoder.decodeString.map[Mailbox](Mailbox.apply)
}
几乎完全描述这种情况的文档位于 Custom encoders/decoders
作为创建自定义 encoders/decoders 的替代方法,您还可以使用 circe extras 中的 deriveUnwrappedEncoder/deriveUnwrappedDecoder
。
只需在你的代码中添加以下导入即可 buid.sbt
:
libraryDependencies += "io.circe" %% "circe-generic-extras" % "xxx"
然后你将能够做到:
import io.circe.generic.extras.semiauto._
implicit val encoder: Encoder[Mailbox] = deriveUnwrappedEncoder
implicit val decoder: Decoder[Mailbox] = deriveUnwrappedDecoder