如何使用Circe为JSON添加嵌套字段及数组类型嵌套字段
问题
如何为JSON对象添加嵌套字段?
我想要生成的不是如下扁平结构:
{ "ExistingField": {}, "Newfield": {} }
而是具备嵌套层级的目标结构:
{ "ExistingField": {}, "A": { "B": { "C": "myStringValue" } }, "AA": { "BB": "myStringValue" } }
已尝试方案
我有一个以.分隔嵌套路径的字符串列表,遍历添加字段后只得到了扁平化的结果,而非预期的嵌套结构:
{ "ExistingField": {}, "A.B.C": "myStringValue" }
字段列表定义如下:
val listOfFields: List[String] = List("A.B.C", "AA.BB")
补充需求:如果要添加的字段是数组类型该怎么办?比如生成如下结构:
{ "ExistingField": {}, "A": { "B": { "C": "myStringValue" } }, "AA": { "BB": [ { "CC": "myStringValue" }, { "CC": "myStringValue" } ] } }
解决方案
1. 生成普通嵌套字段
要实现嵌套结构,需要将.分割的字段路径逐层构建JSON对象,而非直接用完整路径作为键。借助Circe的Json API和递归逻辑可以轻松实现:
import io.circe._ import io.circe.syntax._ // 将字段路径(如"A.B.C")和对应值构建为嵌套Json对象 def pathToNestedJson(path: String, value: Json): Json = { val keys = path.split('.').reverse.toList keys.foldLeft(value) { (currentJson, key) => Json.obj(key -> currentJson) } } // 示例用法 val existingJson = Json.obj("ExistingField" -> Json.obj()) // 定义每个路径对应的取值 val fieldValuePairs = List( "A.B.C" -> "myStringValue".asJson, "AA.BB" -> "myStringValue".asJson ) // 逐个合并嵌套字段到现有JSON val finalJson = fieldValuePairs.foldLeft(existingJson) { (accJson, entry) => val (path, value) = entry val nestedObj = pathToNestedJson(path, value) accJson.deepMerge(nestedObj) } // 打印格式化后的结果 println(finalJson.spaces2)
这段代码会将每个路径拆解为层级键,从最内层的值开始逐层包裹成对象,最后通过deepMerge合并到原有JSON中,得到目标嵌套结构。
2. 生成数组类型的嵌套字段
如果要添加数组类型的值,只需将对应的值替换为Json数组即可,上述工具方法无需修改:
// 构建数组类型的Json值 val targetArray = Json.arr( Json.obj("CC" -> "myStringValue".asJson), Json.obj("CC" -> "myStringValue".asJson) ) // 混合普通字段和数组字段的路径-值对 val mixedFieldPairs = List( "A.B.C" -> "myStringValue".asJson, "AA.BB" -> targetArray ) // 合并生成最终JSON val finalJsonWithArray = mixedFieldPairs.foldLeft(existingJson) { (accJson, entry) => val (path, value) = entry val nestedObj = pathToNestedJson(path, value) accJson.deepMerge(nestedObj) } println(finalJsonWithArray.spaces2)
核心逻辑是用Json.arr创建数组类型的Json实例,再通过相同的路径构建方法生成嵌套结构,最后合并到原有JSON中即可。
内容的提问来源于stack exchange,提问作者Jackson Li
相关产品推荐
相关产品推荐

