Scala中如何实现List[String]到List[Object]的类型转换
Scala 实现 List[String] 到 List[自定义对象] 的转换方案
核心逻辑分两层:一是完成输入输出样例类的字段名映射,二是把字符串列表的每个元素包装成目标自定义对象,以下是两种最常用的实现方式:
方案1:原生Scala无依赖实现(简单场景推荐)
不需要引入第三方库,直接手动写对象转换逻辑即可。首先先修正样例类语法问题:Scala中类关键字是小写class,用于数据承载的类推荐用case class,可以省去大量样板代码:
// 输入对应样例类 case class Office( name: Option[String], employeeBranch: Option[List[String]] ) // 输出对应样例类 case class Branch(branch: Option[String]) case class Output( Name: Option[String], EmployeeBranch: Option[List[Branch]] )
转换逻辑非常直接,利用Option.map处理空值场景避免空指针,对列表元素逐个包装成Branch实例:
def convertOfficeToOutput(office: Office): Output = { Output( Name = office.name, EmployeeBranch = office.employeeBranch.map { strList => strList.map(branchStr => Branch(branch = Some(branchStr))) } ) }
可以用样例数据验证结果:
val testInput = Office( name = Some("test"), employeeBranch = Some(List("CSE", "IT", "ECE")) ) val result = convertOfficeToOutput(testInput) // 输出结果:Output(Some("test"), Some(List(Branch(Some("CSE")), Branch(Some("IT")), Branch(Some("ECE")))))
将这个result用任意JSON库序列化,就能得到期望的输出JSON结构。
注意:不要直接对Option类型调用
.get取值,否则当字段为None时会抛出异常,用map、fold等高阶函数处理空值更安全。
方案2:JSON序列化层直接转换(生产环境推荐)
如果流程是直接接收输入JSON、输出目标JSON,不需要中间的Office样例类,可以直接在JSON编解码器层面完成映射,省去手动转换对象的步骤。以Scala生态常用的Circe库为例:
首先在sbt配置中引入依赖:
libraryDependencies ++= Seq( "io.circe" %% "circe-core" % "0.14.6", "io.circe" %% "circe-generic" % "0.14.6", "io.circe" %% "circe-parser" % "0.14.6" )
给目标类自定义编解码器,完成字段名映射和字符串到Branch对象的转换:
import io.circe._ import io.circe.generic.semiauto._ // 自定义Branch的编解码器:直接把JSON字符串解析为Branch对象 case class Branch(branch: Option[String]) object Branch { implicit val branchDecoder: Decoder[Branch] = Decoder.decodeString.map(str => Branch(Some(str))) implicit val branchEncoder: Encoder[Branch] = deriveEncoder[Branch] } // 自定义Output的编解码器:映射输入JSON的小写字段到输出类的大写字段 case class Output( Name: Option[String], EmployeeBranch: Option[List[Branch]] ) object Output { implicit val outputDecoder: Decoder[Output] = Decoder.forProduct2("name", "employeeBranch")(Output.apply) implicit val outputEncoder: Encoder[Output] = Encoder.forProduct2("Name", "EmployeeBranch")(o => (o.Name, o.EmployeeBranch)) } // 如果输入JSON外层还有employee键,可以再包一层映射结构 case class EmployeeWrap(Employee: Output) object EmployeeWrap { implicit val wrapDecoder: Decoder[EmployeeWrap] = Decoder.forProduct1("employee")(EmployeeWrap.apply) implicit val wrapEncoder: Encoder[EmployeeWrap] = Encoder.forProduct1("Employee")(_.Employee) }
直接解析输入JSON即可得到目标结构:
val inputJson = """{"employee": {"name": "test", "employeeBranch": ["CSE", "IT", "ECE"]}}""" val parseResult = io.circe.parser.parse(inputJson).flatMap(_.as[EmployeeWrap]) // 解析结果:Right(EmployeeWrap(Output(Some("test"),Some(List(Branch(Some("CSE")), Branch(Some("IT")), Branch(Some("ECE")))))))
如果使用Play JSON、Jackson Scala Module等其他JSON库,实现逻辑完全一致:只需要给Branch类型自定义字符串到对象的解析规则,再配置字段名的大小写映射即可。如果项目有统一的大驼峰/小驼峰命名转换规则,也可以直接用库自带的命名策略,不需要手动配置每个字段的映射关系。
常见注意点
- 如果输入的字符串列表中存在空值、空字符串,可以根据业务需求判断是转为
None还是保留Some("") - 列表为空的场景会被自动处理,不需要额外写判断逻辑
- 涉及嵌套Option结构时,优先用
for推导式、高阶函数处理,避免嵌套的空判断逻辑
内容的提问来源于stack exchange,提问作者Senthil
相关产品推荐
相关产品推荐

