You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala Play中如何为两个控制器端点切换隐式JSON格式化器

Scala Play 多版本JSON格式化器切换问题

问题描述

现有基于Scala Play框架开发的接口,返回嵌套结构的复杂JSON配置,配置层级如下:

Configuration    
|__ DBConfig
    |__ SecretDef
|__ SecondDBConfig
    |__ SecretDef
|__ AuthConfig
    |__ SecretDef

序列化该配置共使用20余个隐式格式化器,其中敏感字段类型SecretDef的默认格式化器直接返回原值,实现如下:

implicit val fSecretFormat: Format[SecretDef] = new Format[SecretDef] {
  override def writes(o: SecretDef): JsValue = 
    Json.toJson(o.value)

  override def reads(json: JsValue): JsResult[SecretDef] = ???
}

现需要开发该接口的V2版本,返回完整配置结构,但SecretDef字段的序列化逻辑需替换为AES解密后的值,对应格式化器实现如下:

implicit val fSecretFormatDec: Format[SecretDef] = new Format[SecretDef] {
  override def writes(o: SecretDef): JsValue = 
    Json.toJson(decryptWithAES(o.value))

  override def reads(json: JsValue): JsResult[SecretDef] = ???
}

实际开发中遇到问题:控制器已全局导入所有隐式格式化器,无法在V2端点的单独Action中完成SecretDef隐式格式化器的切换。曾尝试在Action作用域内定义优先级更高的隐式值,写法如下,但未生效:

Action.async { implicit request =>
  implicit val fSecret: Format[SecretDef] = utils.SecretFormatters.fSecretFormatEnc
  for {
    config <- configRepo.getConfig()
  } yield Ok(Json.toJson(tenant))
}

解决方案

参考Gaël J的建议,通过抽象格式化器特质、拆分不同版本实现的方式解决,代码如下:

trait Formatters {
  implicit def getSecretDef: Format[SecretDef]
  // 其余所有依赖SecretDef的隐式格式化器均在此处定义为def
}

// V1版本格式化器:返回SecretDef原值
object JsonFormatters extends Formatters {
  override implicit def getSecretDef: Format[SecretDef] = SecretFormatters.fSecretFormat
}

// V2版本格式化器:返回SecretDef解密后的值
object JsonFormattersV2 extends Formatters {
  override implicit def getSecretDef: Format[SecretDef] = SecretFormatters.fSecretFormatDec
}

使用时无需全局导入格式化器,仅需在对应版本接口的Action作用域内导入对应版本的格式化器对象,即可自动完成序列化逻辑的切换。


内容的提问来源于stack exchange,提问作者zoran jeremic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 10:36:39