如何配置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
相关产品推荐
相关产品推荐

