是否有一种方法可以使用默认的“内置”(宏生成的),并且仅覆盖单个属性?

问题描述 投票:0回答:2

我试图以字符串形式读取字段vpid,而不必编写整个读取函数。

有效的旧代码,除非vpid是整数。

case class SectionProduct(vpid: Option[String], name: Option[String], quantity: Option[Int]) {}

object SectionProduct {
  implicit val config: Aux[WithDefaultValues] = JsonConfiguration[Json.WithDefaultValues](SnakeCase)
  implicit val format: OFormat[SectionProduct] = Json.format[SectionProduct]
  implicit val writes: OWrites[SectionProduct] = Json.writes[SectionProduct]
  // implicit val reads:  Reads[SectionProduct] =   Json.reads[SectionProduct]
}

新代码,如果可能的话,我试图避免写出整个reads2块。

val intToString: Reads[String] = implicitly[Reads[Int]].map(x => x.toString)

implicit val reads2: Reads[SectionProduct] = (
    ((JsPath \ "vpid").readNullable[String] or (JsPath \ "vpid").readNullable[String](intToString)) and
      (JsPath \ "name").readNullable[String] and
      (JsPath \ "quantity").readNullable[Int]
    ) (SectionProduct.apply _)
json scala playframework
2个回答
2
投票

[Play-JSON不为基于宏的编解码器提供每个字段的配置,并且vpid未使用特定类型定义(同一String中还有其他可选的SectionProduct)。] >

使用特定类型,它很容易(并且通过改进键入功能,除了这种特定用法之外,还可以享受其他好处)。>>

import play.api.libs.json._

final class Vpid(val value: String) extends AnyVal

object Vpid {
  import scala.language.implicitConversions

  @deprecated("Use .value explicitly", "")
  /*
   * {{{
   * val compatStr: String = new Vpid("foo")
   * // => compatStr: String = foo
   * }}}
   */
  implicit def toString(id: Vpid): String = id.value

  implicit def reads: Reads[Vpid] = Json.valueReads[Vpid].orElse(
    implicitly[Reads[Int]].map { i => new Vpid(i.toString) })
}

case class SectionProduct(
  vpid: Option[Vpid],
  name: Option[String],
  quantity: Option[Int])

implicit val reads: Reads[SectionProduct] = Json.reads

在这种情况下:

val input1 = Json.parse("""{
  "vpid": "foo",
  "name": "bar"
}""")

input1.validate[SectionProduct]
// => JsSuccess(SectionProduct(Some(Vpid@18cc6),Some(bar),None),)

val input2 = Json.parse("""{
  "vpid": 1,
  "name": "bar"
}""")

input2.validate[SectionProduct]
// => JsSuccess(SectionProduct(Some(Vpid@31),Some(bar),None),)

您可以预处理您的JSON以使其与生成的Reads宏的期望匹配:

implicit val reads: Reads[SectionProduct] = Json.reads[SectionProduct].preprocess {
    case obj: JsObject =>
      obj.as(
        Reads
          .at[Int](__ \ "vpid")
          .map { vpid => obj + ("vpid" -> JsString(vpid.toString)) }
          .orElse(Reads.pure(obj))
      )
  }

1
投票

您可以预处理您的JSON以使其与生成的Reads宏的期望匹配:

© www.soinside.com 2019 - 2024. All rights reserved.