【发布时间】:2017-03-11 09:45:54
【问题描述】:
我想在我的案例类和我的 JSON 中使用不同的字段名称,因此我需要一种舒适的方式来重命名编码和解码。
有人有好的解决方案吗?
【问题讨论】:
我想在我的案例类和我的 JSON 中使用不同的字段名称,因此我需要一种舒适的方式来重命名编码和解码。
有人有好的解决方案吗?
【问题讨论】:
您可以使用Custom key mappings via annotations。最通用的方式是来自io.circe.generic.extras._ 的JsonKey 注解。文档中的示例:
import io.circe.generic.extras._, io.circe.syntax._
implicit val config: Configuration = Configuration.default
@ConfiguredJsonCodec case class Bar(@JsonKey("my-int") i: Int, s: String)
Bar(13, "Qux").asJson
// res5: io.circe.Json = JObject(object[my-int -> 13,s -> "Qux"])
这需要包circe-generic-extras。
【讨论】:
这是解码器的代码示例(有点冗长,因为它不会删除旧字段):
val pimpedDecoder = deriveDecoder[PimpClass].prepare {
_.withFocus {
_.mapObject { x =>
val value = x("old-field")
value.map(x.add("new-field", _)).getOrElse(x)
}
}
}
【讨论】:
implicit val decodeFieldType: Decoder[FieldType] =
Decoder.forProduct5("nth", "isVLEncoded", "isSerialized", "isSigningField", "type")
(FieldType.apply)
如果您有很多不同的字段名称,这是一种简单的方法。 https://circe.github.io/circe/codecs/custom-codecs.html
【讨论】:
您可以使用编码器上的mapJson 函数从通用编码器派生编码器并重新映射您的字段名称。
您可以使用解码器上的prepare 函数将传递给通用解码器的 JSON 转换。
你也可以从头开始写,但它可能是大量的样板,这些解决方案都应该是每个最多几行。
【讨论】:
以下函数可用于重命名circe的JSON字段:
import io.circe._
object CirceUtil {
def renameField(json: Json, fieldToRename: String, newName: String): Json =
(for {
value <- json.hcursor.downField(fieldToRename).focus
newJson <- json.mapObject(_.add(newName, value)).hcursor.downField(fieldToRename).delete.top
} yield newJson).getOrElse(json)
}
您可以像这样在Encoder 中使用它:
implicit val circeEncoder: Encoder[YourCaseClass] = deriveEncoder[YourCaseClass].mapJson(
CirceUtil.renameField(_, "old_field_name", "new_field_name")
)
单元测试
import io.circe.parser._
import org.specs2.mutable.Specification
class CirceUtilSpec extends Specification {
"CirceUtil" should {
"renameField" should {
"correctly rename field" in {
val json = parse("""{ "oldFieldName": 1 }""").toOption.get
val resultJson = CirceUtil.renameField(json, "oldFieldName", "newFieldName")
resultJson.hcursor.downField("oldFieldName").focus must beNone
resultJson.hcursor.downField("newFieldName").focus must beSome
}
"return unchanged json if field is not found" in {
val json = parse("""{ "oldFieldName": 1 }""").toOption.get
val resultJson = CirceUtil.renameField(json, "nonExistentField", "newFieldName")
resultJson must be equalTo json
}
}
}
}
【讨论】: