欢迎关注Hadoop、Spark、Flink、Hive、Hbase、Flume等大数据资料分享微信公共账号:iteblog_hadoop
  1. 文章总数:977
  2. 浏览总数:11,945,073
  3. 评论:3936
  4. 分类目录:106 个
  5. 注册用户数:6113
  6. 最后更新:2018年12月13日
过往记忆博客公众号iteblog_hadoop
欢迎关注微信公众号:
iteblog_hadoop
大数据技术博客公众号bigdata_ai
大数据猿:
bigdata_ai

Play JSON类库将List[(String, String)]转换成Json字符串

  最近在一个项目中使用到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", "https://www.iteblog.com"), ("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", "https://www.iteblog.com"), ("weixin", "iteblog_hadoop"))

println(Json.toJson(info))
[{"web_site":"https://www.iteblog.com"},{"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":"https://www.iteblog.com"},{"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框架发现这个框架真是太方便了,太强大了。。

本博客文章除特别声明,全部都是原创!
转载本文请加上:转载自过往记忆(https://www.iteblog.com/)
本文链接: 【Play JSON类库将List[(String, String)]转换成Json字符串】(https://www.iteblog.com/archives/1753.html)
喜欢 (12)
分享 (0)
发表我的评论
取消评论

表情
本博客评论系统带有自动识别垃圾评论功能,请写一些有意义的评论,谢谢!