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

如何配置Spray JSON实现数组/单个字符串到List[String]的灵活反序列化?

当然可以搞定这种灵活的解析需求!Spray JSON支持自定义格式来处理这种「既接受数组又接受单个元素」的场景,我给你具体的实现方案和代码示例:

1. 实现自定义的灵活List[String]格式

核心思路是创建一个自定义的JsonFormat[List[String]],在反序列化时判断输入的JSON类型:如果是数组就直接解析成列表,如果是单个字符串就把它包装成单元素列表。

import spray.json._

object FlexibleListJsonProtocol extends DefaultJsonProtocol {
  // 自定义List[String]的解析/序列化规则
  implicit val flexibleStringListFormat: JsonFormat[List[String]] = new JsonFormat[List[String]] {
    // 序列化时统一输出为数组,保证输出格式的一致性
    override def write(list: List[String]): JsValue = {
      JsArray(list.map(JsString(_)))
    }

    // 反序列化时兼容数组和单个字符串两种情况
    override def read(json: JsValue): List[String] = json match {
      case JsArray(elements) => elements.map(_.convertTo[String]).toList
      case JsString(value) => List(value)
      // 遇到其他类型直接抛出明确的解析错误
      case invalidType => deserializationError(
        s"Expected either a String or an Array of Strings, got ${invalidType.getClass.getSimpleName}"
      )
    }
  }
}
2. 在业务模型中使用自定义格式

把自定义的协议引入到你的case class代码中,就可以正常解析两种格式的JSON了:

// 引入我们定义的灵活列表协议
import FlexibleListJsonProtocol._

// 你的业务模型类
case class MyData(arrayval: List[String])

// 测试单个字符串的场景
val singleStringJson = """{"arrayval": "a"}""".parseJson
val singleResult = singleStringJson.convertTo[MyData]
// 输出结果: MyData(List(a))

// 测试数组的场景
val arrayJson = """{"arrayval": ["a", "b"]}""".parseJson
val arrayResult = arrayJson.convertTo[MyData]
// 输出结果: MyData(List(a, b))
3. 扩展:通用化处理任意类型的List

如果你需要对其他类型的列表(比如List[Int]、List[Double])做同样的兼容,可以把逻辑抽象成通用方法,避免重复代码:

import spray.json._

object FlexibleListJsonProtocol extends DefaultJsonProtocol {
  // 通用的灵活列表格式生成器
  def flexibleListFormat[T](implicit elementFormat: JsonFormat[T]): JsonFormat[List[T]] = 
    new JsonFormat[List[T]] {
      override def write(list: List[T]): JsValue = JsArray(list.map(elementFormat.write))
      override def read(json: JsValue): List[T] = json match {
        case JsArray(elements) => elements.map(elementFormat.read).toList
        case singleElement => List(elementFormat.read(singleElement))
      }
    }

  // 针对List[String]的具体实例
  implicit val flexibleStringListFormat: JsonFormat[List[String]] = flexibleListFormat[String]
  // 如果需要List[Int],直接这样定义即可
  implicit val flexibleIntListFormat: JsonFormat[List[Int]] = flexibleListFormat[Int]
}

这样不管是什么类型的列表,都能轻松实现「数组/单个元素」的兼容解析啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:25:05