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

Scala 2.12复杂嵌套JSON反序列化至Scala对象方案咨询

解决Scala 2.12中嵌套JSON反序列化到Case Class的问题(含验证逻辑)

针对你的问题,我会先给出Lift-JSON的完整实现方案,再提供一个更现代的轻量替代方案(Circe),两者都不会引入Play重型依赖,同时包含你需要的验证逻辑。


方案一:使用Lift-JSON实现

首先确保你的项目中引入了Lift-JSON的依赖(Scala 2.12对应版本),在sbt中添加:

libraryDependencies += "net.liftweb" %% "lift-json" % "3.4.3"

接下来是完整的代码实现,包含解析、反序列化和验证:

import net.liftweb.json._
import scala.io.Source
import scala.util.Try

// 你的Case Class定义
case class Bar(whistle: Integer, feather: Boolean)
case class MyConfig(fizz: String, foo: Array[String], bar: Bar)

def loadConfig(configFilePath: String): MyConfig = {
  // 初始化Lift-JSON的默认格式规则
  implicit val formats: Formats = DefaultFormats

  // 读取并解析JSON,处理格式错误异常
  val parsedJson = Try {
    val configJson = Source.fromFile(configFilePath).mkString
    parse(configJson)
  }.recover {
    case ex: Exception => throw new IllegalArgumentException(s"JSON文件解析失败:${ex.getMessage}", ex)
  }.get

  // 反序列化为MyConfig实例,处理字段/类型不匹配异常
  val config = Try {
    parsedJson.extract[MyConfig]
  }.recover {
    case ex: MappingException => throw new IllegalArgumentException(s"JSON结构与MyConfig不匹配:${ex.getMessage}", ex)
  }.get

  // 执行自定义业务验证
  validateConfig(config)

  config
}

// 自定义验证函数,可根据需求扩展规则
private def validateConfig(config: MyConfig): Unit = {
  val errors = scala.collection.mutable.ListBuffer[String]()

  // 验证fizz非空
  if (config.fizz.trim.isEmpty) {
    errors += "fizz字段不能为空字符串"
  }

  // 验证foo数组非空且元素有效
  if (config.foo.isEmpty) {
    errors += "foo数组不能为空"
  } else {
    config.foo.zipWithIndex.foreach { case (item, idx) =>
      if (item.trim.isEmpty) {
        errors += s"foo数组第${idx+1}个元素不能为空字符串"
      }
    }
  }

  // 验证bar的whistle值合法(示例:必须大于0)
  if (config.bar.whistle <= 0) {
    errors += "bar.whistle必须大于0"
  }

  // 收集到错误则抛出异常
  if (errors.nonEmpty) {
    throw new IllegalArgumentException(s"配置验证失败:${errors.mkString("; ")}")
  }
}

关键说明:

  • DefaultFormats是Lift-JSON提供的默认序列化/反序列化规则,支持基本类型、数组、嵌套Case Class等常见结构。
  • parse会在JSON格式错误时抛出ParsingException,extract会在字段缺失、类型不匹配时抛出MappingException,我们用Try捕获这些底层异常并包装成更友好的业务异常。
  • 自定义的validateConfig函数可以灵活添加任意业务规则,最后统一抛出验证失败的异常。

方案二:使用Circe(更现代的轻量JSON库)

如果你觉得Lift-JSON的API不够直观,Circe是一个更现代、功能丰富且轻量的JSON库,同样不需要依赖Play核心。

首先添加Circe的依赖(Scala 2.12对应版本):

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

然后是完整实现:

import io.circe._
import io.circe.generic.semiauto._
import io.circe.parser._
import scala.io.Source

// 你的Case Class定义
case class Bar(whistle: Integer, feather: Boolean)
case class MyConfig(fizz: String, foo: Array[String], bar: Bar)

// 自动推导解码器,无需手动编写映射规则
implicit val barDecoder: Decoder[Bar] = deriveDecoder[Bar]
implicit val myConfigDecoder: Decoder[MyConfig] = deriveDecoder[MyConfig]

def loadConfig(configFilePath: String): MyConfig = {
  // 读取JSON文件内容
  val configJson = Source.fromFile(configFilePath).mkString

  // 解析+反序列化,用for-comprehension处理链式错误
  val result = for {
    json <- parse(configJson)
    config <- json.as[MyConfig]
  } yield config

  // 处理错误分支,抛出友好异常
  val config = result match {
    case Right(c) => c
    case Left(ex) => throw new IllegalArgumentException(s"JSON解析或反序列化失败:${ex.getMessage}", ex)
  }

  // 执行自定义验证逻辑
  validateConfig(config)

  config
}

// 自定义验证函数(和Lift-JSON方案通用)
private def validateConfig(config: MyConfig): Unit = {
  val errors = scala.collection.mutable.ListBuffer[String]()

  if (config.fizz.trim.isEmpty) errors += "fizz字段不能为空字符串"
  if (config.foo.isEmpty) errors += "foo数组不能为空"
  config.foo.zipWithIndex.foreach { case (item, idx) =>
    if (item.trim.isEmpty) errors += s"foo数组第${idx+1}个元素不能为空字符串"
  }
  if (config.bar.whistle <= 0) errors += "bar.whistle必须大于0"

  if (errors.nonEmpty) {
    throw new IllegalArgumentException(s"配置验证失败:${errors.mkString("; ")}")
  }
}

关键说明:

  • Circe使用自动推导解码器(deriveDecoder)生成Case Class的反序列化规则,代码更简洁易维护。
  • parse和as方法返回Either[Error, T],通过for-comprehension可以优雅地处理链式操作的错误分支。
  • 验证逻辑和Lift-JSON方案完全通用,不需要额外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:06:30