更改嵌套对象的Scala响应中的隐含值

5fjcxozz  于 2022-11-09  发布在  Scala
关注(0)|答案(1)|浏览(145)

我有一个控制器

def getCars(notation: Option[Boolean] = Some(false)) = identified.auth(hasOceanScope).async { implicit request =>
  carService.getCars().map {
    case Seq() => Response.NotFound
    case cars => Response.Ok(cars)
  }
}

Car Case类如下所示:

case class Car(
  name: String,
  createdAt: LocalDateTimeOffset,
  wheels: Seq[Wheel]
)

object Car{
  implicit val wheelFormat = Wheel.format
  implicit def toOffset(date: LocalDateTime): LocalDateTimeOffset = LocalDateTimeOffset.apply(date)

  implicit val format = Json.format[Car]

case class Wheel(
  name: String,
  createdAt: LocalDateTimeOffset
)

object Wheel{
  implicit val format = Json.format[Wheel]
  implicit def toOffset(date: LocalDateTime): LocalDateTimeWithOffset = LocalDateTimeWithOffset.apply(date)
 )

当记号查询参数为真时->要返回带记号的CreatedAt Car对象和车轮对象字段=>2022-10-22T00:00:00#1当记号查询参数为FALSE->要返回不带记号的CreatedAt Car对象和车轮对象字段=>2022-10-22T00:00:00
这就是为什么我在LocalDateTimeOffset对象中创建了两种格式

case class LocalDateTimeWithOffset(dt: LocalDateTime, offset: Int) {

  val localDateTimeWithOffsetReads: Reads[LocalDateTimeWithOffset] = Reads.of[String].flatMap {
    str => if (str.contains("#")) {
      val (dt, offset) = str.splitAt(str.indexOf("#"))
      Reads.pure(LocalDateTimeWithOffset(LocalDateTime.parse(dt), offset.drop(1).toInt))
    } else {
      Reads.pure(LocalDateTimeWithOffset(LocalDateTime.parse(str), 1))
    }
  }

  val localDateTimeWithOffsetWrites: Writes[LocalDateTimeWithOffset] = new Writes[LocalDateTimeWithOffset] {
    override def writes(a: LocalDateTimeWithOffset): JsValue = JsString(a.dt.format(dateTimeUTCFormatter) + s"#${a.offset}")
  }

  val localDateTimeWithOffsetWritesOff: Writes[LocalDateTimeWithOffset] = new Writes[LocalDateTimeWithOffset] {
    override def writes(a: LocalDateTimeWithOffset): JsValue = JsString(a.dt.format(dateTimeUTCFormatter))
  }

  val localDateTimeWithoutOffsetFormat: Format[LocalDateTimeWithOffset] = Format(localDateTimeWithOffsetReads, localDateTimeWithOffsetWritesOff)
  val localDateTimeWithOffsetFormat: Format[LocalDateTimeWithOffset] = Format(localDateTimeWithOffsetReads, localDateTimeWithOffsetWrites)

  implicit var format: Format[LocalDateTimeWithOffset] = localDateTimeWithoutOffsetFormat
}

但是如何根据符号查询参数值从控制器使用两种不同的格式呢?

jdgnovmf

jdgnovmf1#

好的,看看问题的标题,changing implicit value不是Scala开发人员要做的事情,因为编译器负责查找隐含的值,而您肯定希望避免ambiguous implicits found错误。相反,您会看到开发人员使用所谓的type class instance constructor或类似的东西。这就是它的工作原理在你的情况下
假设您有一个类A,它可以通过多种方式与Json相互格式化:

case class A(field1: String) // could have more fields

object A {
  val formatFirstApproach: Format[A] = ???
  val formatSecondApproach: Format[A] = ???
  // note that the above instances are not implicit
  def getFormat(somePredicate: Boolean): Format[A] = {
  // input parameters can be anything, these are the parameters you need,
  // in order to be able to decide which instance to return
  if (somePredicate) formatFirstApproach else formatSecondApproach
  }
}

然后,给定一个类B,其中有一个A类型的示例变量,您可以使用type class instance constructor

case class B(a: A, field2: Int)

object B {
  // this is the type class instance constructor, since it constructs an instance of a type class (Format in this case)
  implicit def format(implicit aFormatter: Format[A]): Format[B] = Json.format
}

问题是,除非在控制器层中,否则您可能不会关心序列化,所以在控制器层中,您可以:

def someApi(flag: Boolean) = Action async { req => 
  implicit val aFormatter = A.getFormat(flag) // that's it, you don't need to mention anything more anywhere
  businessLogic().map {
    case Seq() => Response.NotFound
    case cars => Response.Ok(Json.toJson(cars))
  }
}

相关问题