Есть ли способ использовать встроенный по умолчанию (сгенерированный макросом) и переопределить только одно свойство? - PullRequest
0 голосов
/ 03 апреля 2020

Я пытаюсь прочитать поле 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 _)

Ответы [ 2 ]

2 голосов
/ 03 апреля 2020

Play- JSON не предоставляет конфигурацию для каждого поля для кодеков на основе макросов, а vpid не определено с указанным типом c (есть другие дополнительные String в том же SectionProduct).

С указанным типом c это может быть легко (и может иметь другие преимущества, кроме этого использования c с улучшенным набором текста).

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),)
1 голос
/ 03 апреля 2020

Вы можете предварительно обработать ваш 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))
      )
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...