假设我们有个需求,需要解析文件里面的Json数据,我们的Json数据如下:
{"website": "www.iteblog.com", "email": "hadoop@iteblog.com"}
我们使用play-json来解析,首先我们引入相关依赖:
<dependency> <groupId>com.typesafe.play</groupId> <artifactId>play-json_2.10</artifactId> <version>2.4.0-M1</version> </dependency>
然后我们会定义一个类来存储解析好的数据,方便后面的操作,如下:
case class BlogInfo(website: String, email: String)
现在我们可以使用下面代码来解析上面的Json数据,并存储到 BlogInfo
类中。每行Json解析后都用 BlogInfo
类表示:
import play.api.libs.functional.syntax._ import play.api.libs.json._ val jsonInfo = """{"website": "www.iteblog.com", "email" : "hadoop@iteblog.com"}""" implicit val WebSiteFormat: Reads[BlogInfo] = ( (JsPath \ "website").read[String] and (JsPath \ "email").read[String] ) (BlogInfo) println(Json.parse(jsonInfo).as[BlogInfo]) //BlogInfo(www.iteblog.com,hadoop@iteblog.com)
我们运行上面的代码,完美地解析了Json数据。但是现实并不是一帆风顺的,我们的Json数据可能有些字段没有,比如文件里面有一行如下格式的数据:
{"website": "www.iteblog.com"}
没有email字段,如果这时候你运行上面的代码会得到下面的异常:
Exception in thread "main" play.api.libs.json.JsResultException: JsResultException(errors:List((/email,List(ValidationError(error.path.missing,WrappedArray()))))) at play.api.libs.json.JsValue$$anonfun$2.apply(JsValue.scala:67) at play.api.libs.json.JsValue$$anonfun$2.apply(JsValue.scala:67) at play.api.libs.json.JsResult$class.fold(JsResult.scala:77) at play.api.libs.json.JsError.fold(JsResult.scala:13) at play.api.libs.json.JsValue$class.as(JsValue.scala:65) at play.api.libs.json.JsObject.as(JsValue.scala:166) at com.iteblog.JsonTest$.main(Test.scala:22) at com.iteblog.JsonTest.main(Test.scala)
这是因为我们解析Json的时候期待 /email
路径,但是我们的Json里面没有,所有会抛出异常。那如何处理呢?本文提供了以下几种解决方案。
使用readNullable解决
既然 email 字段可能不存在,那么我们将 BlogInfo
类中 email 字段设置成 Option[String]
不就可以解决这个问题吗?如下:
case class BlogInfo(website: String, email: Option[String])
这时候我们的WebSiteFormat也需要修改了:
implicit val WebSiteFormat: Reads[BlogInfo] = ( (JsPath \ "website").read[String] and (JsPath \ "email").readNullable[String] ) (BlogInfo) val jsonInfo = """{"website": "www.iteblog.com", "email" : "hadoop@iteblog.com"}""" println(Json.parse(jsonInfo).as[BlogInfo]) val jsonInfo2 = """{"website": "www.iteblog.com"}""" println(Json.parse(jsonInfo2).as[BlogInfo]) Output: BlogInfo(www.iteblog.com,Some(hadoop@iteblog.com)) BlogInfo(www.iteblog.com,None)
现在这个程序完美解决 Json 数据了,不管Json数据里面是否存在 email 字段。如果存在的话返回 Some(xxx)
;如果不存在,直接返回 None
。
使用formatNullable
除了使用 readNullable
函数,我们还可以使用 formatNullable
函数,而且 formatNullable
函数功能更强大,我们当需要的字段不存在,我们可以设置默认值。而且我们还可以存成 Option[Type]
或者直接是 Type
类型的。,使用如下:
///////////////////////////////////////////////////////////////////// User: 过往记忆 Date: 2017年08月02日 Time: 21:57:32 bolg: https://www.iteblog.com 本文地址:https://www.iteblog.com/archives/2222 过往记忆博客,专注于hadoop、hive、spark、shark、flume的技术博客,大量的干货 过往记忆博客微信公共帐号:iteblog_hadoop ///////////////////////////////////////////////////////////////////// case class BlogInfo(website: String, email: Option[String]) implicit val WebSiteFormat: Reads[BlogInfo] = ( (JsPath \ "website").read[String] and (JsPath \ "email").formatNullable[String].inmap[Option[String]](a => Some(a.getOrElse("No Email")), b => b) ) (BlogInfo) val jsonInfo = """{"website": "www.iteblog.com", "email" : "hadoop@iteblog.com"}""" println(Json.parse(jsonInfo).as[BlogInfo]) val jsonInfo2 = """{"website": "www.iteblog.com"}""" println(Json.parse(jsonInfo2).as[BlogInfo]) Output: BlogInfo(www.iteblog.com,Some(hadoop@iteblog.com)) BlogInfo(www.iteblog.com,Some(No Email)) ##################################################### case class BlogInfo(website: String, email: String) implicit val WebSiteFormat: Reads[BlogInfo] = ( (JsPath \ "website").read[String] and (JsPath \ "email").formatNullable[String].inmap[String](_.getOrElse("No Email!"), Some(_)) ) (BlogInfo) val jsonInfo = """{"website": "www.iteblog.com", "email" : "hadoop@iteblog.com"}""" println(Json.parse(jsonInfo).as[BlogInfo]) val jsonInfo2 = """{"website": "www.iteblog.com"}""" println(Json.parse(jsonInfo2).as[BlogInfo]) Output: BlogInfo(www.iteblog.com,hadoop@iteblog.com) BlogInfo(www.iteblog.com,No Email!)
使用Reads.pure
另外一种办法是使用 Reads.pure
,当 read
失败的时候会使用 Reads.pure
函数,我们可以通过它指定一个默认值,具体使用如下:
case class BlogInfo(website: String, email: String) implicit val WebSiteFormat: Reads[BlogInfo] = ( (JsPath \ "website").read[String] and ((JsPath \ "email").read[String] or Reads.pure("No Email!")) ) (BlogInfo) val jsonInfo = """{"website": "www.iteblog.com", "email" : "hadoop@iteblog.com"}""" println(Json.parse(jsonInfo).as[BlogInfo]) val jsonInfo2 = """{"website": "www.iteblog.com"}""" println(Json.parse(jsonInfo2).as[BlogInfo]) Output: BlogInfo(www.iteblog.com,hadoop@iteblog.com) BlogInfo(www.iteblog.com,No Email!)
从上面看出,Play 的 Json 库提供的功能真是强大,可以解决很多麻烦的问题,更多关于 play-json 的使用请参见官方文档了,这里就不再介绍了。
本博客文章除特别声明,全部都是原创!原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【play-json处理空值的几种方法】(https://www.iteblog.com/archives/2222.html)