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

如何使用Scala Circe-Json编码器生成指定格式JSON并解决嵌套数组对象编码问题

使用Scala Circe生成嵌套结构JSON的解决方案

首先,我来帮你梳理下问题:你想要生成特定嵌套结构的JSON,但目前遇到了两个核心问题:一是Circe找不到隐式编码器导致编译错误,二是你的Case Class设计和目标JSON结构不匹配,没法正确映射嵌套数组和对象。

先解决编译错误:导入Circe自动编码器

你看到的Unspecified value parameter encoder错误,是因为Circe需要隐式的Encoder实例来将Case Class转换为JSON,但你没有导入自动派生编码器的包。解决这个很简单,在代码开头加上:

import io.circe._
import io.circe.generic.auto._
import io.circe.syntax._

同时要确保你的build.sbt里包含Circe的必要依赖:

libraryDependencies ++= Seq(
  "io.circe" %% "circe-core" % "0.14.6",
  "io.circe" %% "circe-generic" % "0.14.6",
  "io.circe" %% "circe-parser" % "0.14.6"
)

匹配目标JSON的Case Class设计

目标JSON的结构是多层嵌套的,我们需要逐层设计Case Class来对应。这里有两种方案:类型安全的ADT方案(推荐,避免错误)和简化的Map方案(快速实现)。

方案一:类型安全的ADT方案

这种方案用代数数据类型(ADT)来表示JSON中那些只有单个key的对象,确保类型安全:

import io.circe._
import io.circe.generic.auto._
import io.circe.syntax._

// 对应read.parq中的元素:{"str":""} 或 {"tab":""}
sealed trait ReadParqElement
case class StrElement(str: String) extends ReadParqElement
case class TabElement(tab: String) extends ReadParqElement

// 对应read中的parq数组包装
case class ReadParq(parq: List[ReadParqElement])
// 对应read部分
case class Read(read: List[ReadParq])

// 对应transform.transform中的元素:{"col":""} 或 {"col_def":""}
sealed trait TransformElement
case class ColElement(col: String) extends TransformElement
case class ColDefElement(col_def: String) extends TransformElement

// 对应transform中的transform数组包装
case class TransformInner(transform: List[TransformElement])
// 对应transform部分
case class Transform(transform: List[TransformInner])

// 对应write.parq中的元素:{"path":""}
case class WriteParqPath(path: String)
// 对应write中的parq数组包装
case class WriteParq(parq: List[WriteParqPath])
// 对应write部分
case class Write(write: List[WriteParq])

// 对应action1的完整结构
case class Action1(read: Read, transform: Transform, write: Write)
// 对应actions部分
case class Actions(actions: Map[String, Action1])
// 最外层根结构
case class Root(actions: Actions)

// 为ADT自定义编码器,确保生成单key的JSON对象(而非Circe默认的ADT格式)
implicit val readParqElementEncoder: Encoder[ReadParqElement] = Encoder.instance {
  case StrElement(s) => Json.obj("str" -> Json.fromString(s))
  case TabElement(t) => Json.obj("tab" -> Json.fromString(t))
}

implicit val transformElementEncoder: Encoder[TransformElement] = Encoder.instance {
  case ColElement(c) => Json.obj("col" -> Json.fromString(c))
  case ColDefElement(cd) => Json.obj("col_def" -> Json.fromString(cd))
}

object JsonGenerator extends App {
  // 构建实例,填充目标值(这里用空字符串对应需求)
  val read = Read(List(ReadParq(List(StrElement(""), TabElement("")))))
  val transform = Transform(List(TransformInner(List(ColElement(""), ColDefElement("")))))
  val write = Write(List(WriteParq(List(WriteParqPath("")))))
  
  val action1 = Action1(read, transform, write)
  val root = Root(Actions(Map("action1" -> action1)))
  
  // 生成格式化的JSON并打印
  println(root.asJson.spaces2)
}

方案二:简化的Map方案

如果追求快速实现,也可以用Map[String, String]来表示那些单key的对象,代价是损失类型安全:

import io.circe._
import io.circe.generic.auto._
import io.circe.syntax._

case class ReadParq(parq: List[Map[String, String]])
case class Read(read: List[ReadParq])

case class TransformInner(transform: List[Map[String, String]])
case class Transform(transform: List[TransformInner])

case class WriteParq(parq: List[Map[String, String]])
case class Write(write: List[WriteParq])

case class Action1(read: Read, transform: Transform, write: Write)
case class Actions(actions: Map[String, Action1])
case class Root(actions: Actions)

object JsonGenerator extends App {
  val read = Read(List(ReadParq(List(Map("str" -> ""), Map("tab" -> "")))))
  val transform = Transform(List(TransformInner(List(Map("col" -> ""), Map("col_def" -> "")))))
  val write = Write(List(WriteParq(List(Map("path" -> "")))))
  
  val action1 = Action1(read, transform, write)
  val root = Root(Actions(Map("action1" -> action1)))
  
  println(root.asJson.spaces2)
}

为什么你之前的代码出错?

  1. 缺少编码器导入:没有导入circe.generic.auto._,Circe无法自动为你的Case Class生成编码器。
  2. 类型不匹配:你的Rparquet接收List[Map[String,String]],但你传入的是List(rpath("hdfs"), rtab("test_table")),这两个是Case Class实例,不是Map,导致类型不兼容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 21:47:44