最近在一个项目中使用到Play的Json相关的类库,看名字就知道这是和Json打交道的类库。其可以很方面地将class转换成Json字符串;也可以将Json字符串转换成一个类。一般的转换直接看Play的相关文档即可很容易的搞定,将class转换成Json字符串直接写个Writes
即可;而将Json字符串转换成一个类直接写个Reads
即可。所有的操作只需要引入play.api.libs.json._
即可。
但昨天在将List[(String, String)]
类型的对象转换成Json遇到了一点麻烦。如果是List[String]
我们可以这么写:
val list = List("www", "iteblog", "com") println(Json.toJson(list).toString()) ["www","iteblog","com"]
可以直接转换成一个Json数组,如果List[(String, String)]
也那么写行不行呢?
val info = List(("web_site", ""), ("weixin", "iteblog_hadoop")) println(Json.toJson(info))
上面代码还没运行,在编译的时候就出现问题了(这个很不错,错误出现越早越好!):
Error:(15, 24) No Json serializer found for type List[(String, String)]. Try to implement an implicit Writes or Format for this type. println(Json.toJson(info)) ^
上面的错误大概的意思就是Play Json框架找不到如何将List[(String, String)]
类型的对象序列化成Json,需要我们指定一个Writes
或者Format
告诉Play Json框架如何将它序列化成Json。我们先来看看Json.toJson
方法的原型:
def toJson[T](o: T)(implicit tjs: Writes[T]): JsValue
这个方法其实接受两个参数,其中Writes
是通过隐式传入的。有些人可能会问:那为什么上面将List[String]
转换成Json却不要写Writes
呢?原因很简单,因为对于这些基本的类型,Play Json框架已经内置了这些Writes
:
/** * Serializer for Int types. */ implicit object IntWrites extends Writes[Int] { def writes(o: Int) = JsNumber(o) } /** * Serializer for Short types. */ implicit object ShortWrites extends Writes[Short] { def writes(o: Short) = JsNumber(o) } /** * Serializer for Long types. */ implicit object LongWrites extends Writes[Long] { def writes(o: Long) = JsNumber(o) } /** * Serializer for Float types. */ implicit object FloatWrites extends Writes[Float] { def writes(o: Float) = JsNumber(o) } /** * Serializer for Double types. */ implicit object DoubleWrites extends Writes[Double] { def writes(o: Double) = JsNumber(o) } /** * Serializer for BigDecimal types. */ implicit object BigDecimalWrites extends Writes[BigDecimal] { def writes(o: BigDecimal) = JsNumber(o) } /** * Serializer for Boolean types. */ implicit object BooleanWrites extends Writes[Boolean] { def writes(o: Boolean) = JsBoolean(o) } /** * Serializer for String types. */ implicit object StringWrites extends Writes[String] { def writes(o: String) = JsString(o) } /** * Serializer for Jackson JsonNode */ implicit object JsonNodeWrites extends Writes[JsonNode] { def writes(o: JsonNode): JsValue = JacksonJson.jsonNodeToJsValue(o) } /** * Serializer for Array[T] types. */ implicit def arrayWrites[T: ClassTag](implicit fmt: Writes[T]): Writes[Array[T]] = new Writes[Array[T]] { def writes(ts: Array[T]) = JsArray((ts.map(t => toJson(t)(fmt))).toList) }
可以从上面看出,基本类型转换已经内置了,所以我们根本不需要自己定义Writes
。但是List[(String,String)]
并不是内置的类型,所以我们需要自己定义一个Writes
。根据上面内置的Writes
启发,我们可以这么定义一个(String,String)
类型的Writes
如下:
implicit object iteblogWrites extends Writes[(String, String)] { def writes(o: (String, String)) = Json.obj(o._1 -> o._2) }
然后我们再将上面List[(String,String)]
对象转换成Json:
val info = List(("web_site", ""), ("weixin", "iteblog_hadoop")) println(Json.toJson(info)) [{"web_site":""},{"weixin":"iteblog_hadoop"}]
可以看出,经过自定义iteblogWrites
已经告诉Play Json框架如何系列化List[(String,String)]
类型的对象了!如果List[(String,String)]
定义在一个case class中又该如何弄,如下:
case class IteblogInfo(blog: String, blogInfo: List[(String, String)]) val iteblogInfo = IteblogInfo("iteblog", info) println(Json.toJson(iteblogInfo))
运行上面代码也会出错,我们需要告诉Play Json框架如何系列化IteblogInfo
类型成Json,如下:
implicit val IteblogInfoWrites: Writes[IteblogInfo] = ( (JsPath \ "blog").write[String] and (JsPath \ "blogInfo").write[List[(String,String)]] ) (unlift(IteblogInfo.unapply))
这样运行上面的代码得到如下的结果:
{"blog":"iteblog","blogInfo":[{"web_site":""},{"weixin":"iteblog_hadoop"}]}
当然,定义Writes
的方法有很多,上面的例子我们还可以这么定义一个Writes
,如下:
implicit val IteblogInfoWrites: Writes[IteblogInfo] = ( (JsPath \ "iteblog").write[String] and (JsPath \ "blogInfo").write[JsArray] .contramap[List[(String, String)]](list => JsArray(list.map(g => Json.obj(g._1 -> g._2)))) ) (unlift(IteblogInfo.unapply))
这样也可以得到正确的结果。在使用Play Json框架发现这个框架真是太方便了,太强大了。。
本博客文章除特别声明,全部都是原创!原创文章版权归过往记忆大数据(过往记忆)所有,未经许可不得转载。
本文链接: 【Play JSON类库将List[(String, String)]转换成Json字符串】(https://www.iteblog.com/archives/1753.html)