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

在Scala中使用spray-json解析动态命名JSON对象的方法

用spray-json解析带GUID键的JSON方案

嘿,这个问题我之前也碰到过,spray-json处理这种带动态GUID键的JSON其实挺顺手的,不用折腾复杂的自定义读取器,咱们一步步来搞定:

1. 匹配JSON结构定义case class

首先看你的JSON结构:外层有个referredEntities字段,它的值是以GUID字符串为键、实体对象为值的映射。我们直接用Scala的Map[String, T]来对应这个结构,先把各个层级的case class定义好:

// 定义attributes子结构
case class Attributes(owner: String, qualifiedName: String, name: String)

// 定义每个GUID对应的实体对象
case class Entity(typeName: String, attributes: Attributes)

// 定义最外层的根对象
case class ReferredEntitiesResponse(referredEntities: Map[String, Entity])

2. 导入spray-json的必要依赖和默认格式

spray-json提供了基础类型、Map、case class的默认格式支持,先导入这些:

import spray.json._
import DefaultJsonProtocol._ // 导入默认的序列化/反序列化规则

3. 为自定义case class派生JsonFormat

spray-json可以通过jsonFormatN系列方法自动生成case class的JsonFormat,N对应case class的字段数量:

// Attributes有3个字段,用jsonFormat3
implicit val attributesFormat: RootJsonFormat[Attributes] = jsonFormat3(Attributes)
// Entity有2个字段,用jsonFormat2
implicit val entityFormat: RootJsonFormat[Entity] = jsonFormat2(Entity)
// 根对象有1个字段,用jsonFormat1
implicit val responseFormat: RootJsonFormat[ReferredEntitiesResponse] = jsonFormat1(ReferredEntitiesResponse)

4. 实际解析演示

现在就可以直接解析你的JSON字符串了:

// 补全闭合括号后的原始JSON字符串
val jsonStr = """{ "referredEntities":{ "012e2ec1-c205-4657-81d7-1e06eac1a849":{ "typeName":"type1", "attributes":{ "owner":"dave", "qualifiedName":"test", "name":"test" } } } }"""

// 解析并转换为自定义case class
val parsedResponse = jsonStr.parseJson.convertTo[ReferredEntitiesResponse]

// 正常使用解析后的对象
val targetEntity = parsedResponse.referredEntities("012e2ec1-c205-4657-81d7-1e06eac1a849")
println(targetEntity.typeName) // 输出: type1
println(targetEntity.attributes.owner) // 输出: dave

可选:类型安全的UUID键处理

如果你希望GUID键是类型安全的UUID而不是字符串,可以自定义一个UUID的JsonFormat,这样Map的键就能直接用UUID类型:

import java.util.UUID

// 自定义UUID的序列化/反序列化规则
implicit val uuidFormat: RootJsonFormat[UUID] = new RootJsonFormat[UUID] {
  override def write(uuid: UUID): JsValue = JsString(uuid.toString)
  override def read(json: JsValue): UUID = json match {
    case JsString(uuidStr) => UUID.fromString(uuidStr)
    case _ => deserializationError("Expected valid UUID string")
  }
}

// 修改根对象的Map键类型为UUID
case class ReferredEntitiesResponse(referredEntities: Map[UUID, Entity])

// 重新派生根对象的JsonFormat
implicit val responseFormat: RootJsonFormat[ReferredEntitiesResponse] = jsonFormat1(ReferredEntitiesResponse)

这样解析出来的referredEntities就是Map[UUID, Entity],能避免无效的GUID字符串,更安全。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:16:52