Scala:遍历Map与对象数组构建JSON时处理非字符串类型
在Scala中使用Play Framework的Json库遍历Map和对象数组构建JSON时,遇到Double、LocalDate等非字符串类型被强制转换为字符串的问题,导致生成的JSON不符合预期类型。
原示例代码
import play.api.libs.json._ import java.time.Instant import scala.util.Random val Name: Array[String] = Array("Tester1","Tester2","Tester3") val Typeids: Array[String] = Array("00000000-0000-0000-0000-000000000302","00000000-0000-0000-0000-000000003272","00000000-0000-0000-0000-000000006272") val values: Array[Any] = Array(1264.3, java.time.LocalDate.now, "For Testing") val i = 0 val data1 = (i to 2) .map { r => Json.toJson(Map( "Name" -> Json.toJson(s"${Name(r%Name.length)}"), "typeId" -> Json.toJson(s"${Random.shuffle(Typeids.toList).head}"), "value" -> Json.toJson(s"${values(r%values.length)}"))) } val data2 = Json.toJson(data1) println(data2)
当前生成的JSON结果
[{"Name":"Tester1","typeId":"00000000-0000-0000-0000-000000006272","value":"1264.3"},{"Name":"Tester2","typeId":"00000000-0000-0000-0000-000000000302","value":"2022-10-19"},{"Name":"Tester3","typeId":"00000000-0000-0000-0000-000000006272","value":"For Testing"}]
期望的JSON结果
[{"Name":"Tester1","typeId":"00000000-0000-0000-0000-000000006272","value":1264.3},{"Name":"Tester2","typeId":"00000000-0000-0000-0000-000000000302","value":"2022-10-19"},{"Name":"Tester3","typeId":"00000000-0000-0000-0000-000000006272","value":"For Testing"}]
问题原因
- 字符串插值强制转换:原代码中使用
s"${values(r%values.length)}"将所有类型的值统一转为字符串,Json.toJson接收的参数都是字符串类型,因此生成的JSON值会带引号。 - LocalDate无默认JSON格式:Play Framework的Json库默认不支持
java.time.LocalDate的序列化,需要自定义格式规则。
解决方法及修正代码
关键步骤
- 移除字符串插值,保留值的原始类型
- 为
LocalDate自定义JSON序列化格式 - 通过模式匹配处理
Any类型的值,根据实际类型生成对应类型的JSON值
修正后的代码
import play.api.libs.json._ import java.time.LocalDate import java.time.format.DateTimeFormatter import scala.util.Random // 为LocalDate自定义JSON格式:序列化为ISO日期字符串 implicit val localDateFormat: Format[LocalDate] = Format( Reads.localDateReads(DateTimeFormatter.ISO_LOCAL_DATE), Writes.localDateWrites(DateTimeFormatter.ISO_LOCAL_DATE) ) val names: Array[String] = Array("Tester1","Tester2","Tester3") val typeIds: Array[String] = Array("00000000-0000-0000-0000-000000000302","00000000-0000-0000-0000-000000003272","00000000-0000-0000-0000-000000006272") val values: Array[Any] = Array(1264.3, LocalDate.now, "For Testing") val data1 = (0 to 2).map { r => val currentValue = values(r % values.length) // 根据值的实际类型生成对应的JsValue val valueJson = currentValue match { case d: Double => Json.toJson(d) case ld: LocalDate => Json.toJson(ld) case s: String => Json.toJson(s) case other => Json.toJson(other.toString) // 兜底处理其他未匹配类型 } Json.toJson(Map( "Name" -> Json.toJson(names(r % names.length)), "typeId" -> Json.toJson(Random.shuffle(typeIds.toList).head), "value" -> valueJson )) } val data2 = Json.toJson(data1) println(data2)
修正后输出结果
[{"Name":"Tester1","typeId":"00000000-0000-0000-0000-000000006272","value":1264.3},{"Name":"Tester2","typeId":"00000000-0000-0000-0000-000000000302","value":"2022-10-19"},{"Name":"Tester3","typeId":"00000000-0000-0000-0000-000000006272","value":"For Testing"}]
内容的提问来源于stack exchange,提问作者RUDRA GANESH SUBBARAYULU

