Spray-Json序列化None为null:Akka-HTTP迁移API兼容问题
解决Spray-Json序列化Option[Error]时保留"error":null的问题
我之前做REST API迁移的时候也碰到过一模一样的问题——Spray-Json默认会把Option类型的None字段直接省略,但旧API要求必须保留error字段并设为null才能兼容。其实有两种靠谱的解决办法,看你需求选:
方法一:为Response类自定义JsonFormat(精准控制)
如果只有Response这个类需要保留error字段,最稳妥的方式是手动实现它的RootJsonFormat,强制序列化时输出error字段,None就对应JsNull。
import spray.json._ // 先定义你的Result和Error样例类 case class Result(data: String) case class Error(message: String) case class Response(result: Result, error: Option[Error]) // 自定义Json协议 object ApiJsonProtocol extends DefaultJsonProtocol { // 先给Result和Error生成默认的Format implicit val resultFormat: RootJsonFormat[Result] = jsonFormat1(Result) implicit val errorFormat: RootJsonFormat[Error] = jsonFormat1(Error) // 手动实现Response的Format implicit val responseFormat: RootJsonFormat[Response] = new RootJsonFormat[Response] { override def write(response: Response): JsValue = JsObject( "result" -> response.result.toJson, // 不管error是Some还是None,都写入字段,None时用JsNull "error" -> response.error.map(_.toJson).getOrElse(JsNull) ) override def read(json: JsValue): Response = { val jsObj = json.asJsObject Response( jsObj.fields("result").convertTo[Result], // 反序列化时处理error字段:存在则转成Option[Error],不存在则设为None jsObj.fields.get("error").flatMap { case JsNull => None case jsVal => Some(jsVal.convertTo[Error]) } ) } } }
这样序列化Response(Result("test"), None)的时候,就会得到你要的结果:
{ "result": { "data": "test" }, "error": null }
方法二:全局修改Option的序列化规则(批量生效)
如果你的整个项目都需要让所有Option类型的None都输出为null(而不是省略),可以重写默认协议里的optionFormat:
import spray.json._ // 自定义默认协议,覆盖Option的Format object GlobalCustomJsonProtocol extends DefaultJsonProtocol { override protected def optionFormat[T: JsonFormat]: JsonFormat[Option[T]] = new JsonFormat[Option[T]] { override def write(option: Option[T]): JsValue = option match { case Some(value) => value.toJson case None => JsNull // None时输出JsNull,而不是省略字段 } override def read(json: JsValue): Option[T] = json match { case JsNull => None case jsValue => Some(jsValue.convertTo[T]) } } }
之后在需要序列化的地方导入GlobalCustomJsonProtocol._,而不是默认的DefaultJsonProtocol._,所有Option字段的None都会被序列化为null。
注意:这个方法会影响所有使用该协议的Option字段,如果其他地方需要保留默认省略None的行为,就别用这个,选方法一更合适。
内容的提问来源于stack exchange,提问作者Yair Halberstadt
相关产品推荐
相关产品推荐

