Scala中用ScalaObjectMapper解析JSON遇问题:case class解析返回null
我帮你分析下问题所在,以及怎么解决——你遇到的null问题根源是你的Case Class结构和JSON数据完全不匹配,Jackson(应该是用的ObjectMapper吧)没法完成正确的映射,所以返回了null。
先理清楚你的核心问题:
1. 先修正JSON的语法小问题
你的原始JSON里"general": { "table": "123", },多了一个多余的尾逗号,部分JSON解析器会因此报错,先去掉它,修正后的JSON是:
{
"general": { "table": "123" },
"employee" : { "table": "employee_data" },
"fulltime" : { "table": "fulltime_employee_data" },
"consultant" : { "table": "consultant_employee_data" }
}
2. Case Class与JSON结构不匹配的核心点
你定义的Case Class是:
case class EmployeeInfo(employees: List[Map[String, String]])
它期望JSON里有一个名为employees的列表字段,但你的JSON里根本没有这个字段——而是直接有4个顶级键:general、employee、fulltime、consultant,每个键对应一个包含table字段的对象。这种结构不匹配直接导致Jackson无法映射,最终返回null。
3. 两种解决方案,根据你的需求选择
方案一:完全匹配JSON的固定顶级字段结构
如果你的JSON顶级字段是固定的(就这4个),那可以定义完全匹配的Case Class:
// 先定义子对象的Case Class,对应每个顶级键的值结构 case class TableInfo(table: String) // 顶级Case Class,对应JSON的四个顶级键 case class EmployeeInfo( general: TableInfo, employee: TableInfo, fulltime: TableInfo, consultant: TableInfo )
然后用ObjectMapper解析(记得要引入Scala的Jackson模块,否则没法解析Case Class):
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.scala.DefaultScalaModule val mapper = new ObjectMapper() // 注册Scala模块,支持Case Class、List、Map等Scala类型 mapper.registerModule(DefaultScalaModule) val jsonStr = """{ "general": { "table": "123" }, "employee" : { "table": "employee_data" }, "fulltime" : { "table": "fulltime_employee_data" }, "consultant" : { "table": "consultant_employee_data" } }""" // 解析成EmployeeInfo对象 val employeeInfo = mapper.readValue(jsonStr, classOf[EmployeeInfo]) println(employeeInfo) // 输出:EmployeeInfo(TableInfo(123),TableInfo(employee_data),TableInfo(fulltime_employee_data),TableInfo(consultant_employee_data))
方案二:把动态顶级字段统一放到Map/列表里
如果你的JSON顶级字段可能变化,或者你想把它们统一放到employees集合里,可以调整Case Class,并用Jackson的注解处理动态字段:
import com.fasterxml.jackson.annotation.JsonAnySetter import scala.collection.mutable // 子对象结构不变 case class TableInfo(table: String) // 用注解把所有顶级字段都收集到employees Map里 case class EmployeeInfo() { val employees: mutable.Map[String, TableInfo] = mutable.Map.empty // 这个注解会把JSON里所有未匹配的顶级键值对都添加到employees里 @JsonAnySetter def addEmployee(key: String, value: TableInfo): Unit = { employees.put(key, value) } }
解析代码和方案一类似,解析后employeeInfo.employees就会包含所有顶级键对应的TableInfo对象。
额外提示
如果你之前没配置Jackson的错误处理,默认情况下如果遇到未知字段(比如你的JSON里没有employees字段),Jackson不会报错,而是返回null。如果想让它报错提示结构不匹配,可以加上:
mapper.configure(com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true)
这样下次结构不匹配时会直接抛出异常,更容易排查问题。
内容的提问来源于stack exchange,提问作者Nick01

