在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
相关产品推荐
相关产品推荐

