假设我们有个需求,需要解析文件里面的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)


