有没有办法使用默认的 "built-in"(宏生成的)并且只覆盖单个 属性?
Is there a way to use the default "built-in" (macro-generated) and only override the single property?
我正在尝试将字段 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 以使其符合生成的宏的预期 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))
)
}
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),)
我正在尝试将字段 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 以使其符合生成的宏的预期 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))
)
}
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),)