Play Json Parser:解析时忽略字段及Scala多结构JSON解析问题
解决Scala Play JSON中同一字段多结构的解析问题
这个问题挺常见的——JSON结构不一致确实头疼!好在Play JSON的自定义Reads可以帮我们灵活处理这种同一字段同时是对象和数组的情况,我给你一个具体的解决方案:
核心思路
我们需要为Company类编写一个自定义的Reads,通过模式匹配判断输入的JSON是对象还是数组,分别做解析处理:
- 如果是对象:直接用默认的解析逻辑转成
Company实例 - 如果是数组:取数组中的第一个字符串元素作为
Company的name字段
完整代码实现
首先保留你的样例类定义,然后修改Company的伴生对象,添加自定义的Reads:
import play.api.libs.json._ case class Company(name: String) case class User(id: String, name: String, company: Company) object Company { // 自定义Reads,处理对象/数组两种情况 implicit val companyReads: Reads[Company] = Reads { json => json match { // 处理对象类型的company case obj: JsObject => Json.fromJson[Company](obj) // 处理数组类型的company:取第一个字符串元素作为name case JsArray(elements) if elements.nonEmpty => elements.head.validate[String].map(Company(_)) // 其他不合法的JSON结构返回错误提示 case _ => JsError("Expected either a Company object or an array containing a company name") } } // 如果需要序列化(把对象转成JSON),保留默认的Writes implicit val companyWrites: Writes[Company] = Json.writes[Company] // 组合Reads和Writes成Format implicit val companyFormat: Format[Company] = Format(companyReads, companyWrites) } object User { // User的Format可以直接用默认生成的,因为Company的Format已经处理了两种情况 implicit val userFormat: Format[User] = Json.format[User] }
测试验证
现在你可以用这个代码解析你的两个JSON示例了:
// 解析json-1(对象类型的company) val json1 = Json.parse("""{"id": "123456", "name": "james", "company": {"name": "knoldus"}}""") val result1 = json1.validate[User] // result1应该是JsSuccess(User("123456", "james", Company("knoldus"))) // 解析json-2(数组类型的company) val json2 = Json.parse("""{"id": "123456", "name": "james", "company": ["knoldus"]}""") val result2 = json2.validate[User] // result2同样会成功,得到和result1一样的User实例
可选调整
如果你的数组可能为空,或者数组里有多个元素,你可以修改数组分支的逻辑:
- 比如数组为空时返回默认值:
JsSuccess(Company("Unknown")) - 或者取数组最后一个元素:
elements.last.validate[String].map(Company(_))
内容的提问来源于stack exchange,提问作者Harmeet Singh Taara
相关产品推荐
相关产品推荐

