到目前为止,Scala 环境下至少存在6种 Json 解析的类库,这里面不包括 Java 语言实现的 Json 类库。所有这些库都有一个非常相似的抽象语法树(AST)。而 json4s 项目旨在提供一个单一的 AST 树供其他 Scala 类库来使用。

json4s 的使用非常的简单,它可以将类直接转换成 json 格式输出,也支持将 json 格式的数据转换成 class 对象。对于 Scala 和 Java 常见的类型(比如String、Int、java.lang.Integer、java.lang.Long、java.lang.Boolean 等)都提供了相应的转换函数。比如下面我们直接将一个类转换成 json:

import org.json4s.JsonAST.{JNull, JString}
import org.json4s.{DefaultFormats, Extraction, Formats}
import org.json4s.jackson.JsonMethods.render
import org.json4s.jackson.JsonMethods.pretty case class Person(name: String, age: Int)
implicit val formats: Formats = DefaultFormats val person = Person("iteblog", )
val jvalue = Extraction.decompose(person) println(pretty(render(jvalue))) 输出
{
"name" : "iteblog",
"age" :
}

同时我们也可以直接将一个 json 对象转换成类对象:

val person =  Extraction.extract[Person](jvalue)
println(person) 输出
Person(iteblog,)

我们可以看到上面的例子使用起来都很简单的。但是如果碰到元素的类型在 json4s 中没有事先定义,结果会怎么样呢?比如在 json4s 中并没有定义对 java.sql.Date 类型的解析,那如果我们用到了这个类型,会出现什么问题呢?具体如下:

case class Person(name: String, age: Int, birthday: Date)
implicit val formats: Formats = DefaultFormats val person = Person("iteblog", , Date.valueOf("2019-07-01"))
val jvalue = Extraction.decompose(person) println(pretty(render(jvalue))) 输出 {
"name" : "iteblog",
"age" : ,
"birthday" : { }
}

可以从上面的结果看出,json4s 并没有正确的解析出 birthday 字段的值。 如果我们将 json 解析到类中,会出现什么问题呢?

val jvalue1 = parse("""{"name" : "iteblog", "age" : 110, "birthday" : "--"}""")
val person = Extraction.extract[Person](jvalue1)
println(person)

结果

Exception in thread "main" org.json4s.package$MappingException: No usable value for birthday
Parsed JSON values do not match with class constructor
args=
arg types=
executable=Executable(Constructor(public java.sql.Date(int,int,int)))
cause=wrong number of arguments
types comparison result=MISSING(int),MISSING(int),MISSING(int)
at org.json4s.reflect.package$.fail(package.scala:)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$.apply(Extraction.scala:)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$.apply(Extraction.scala:)
at scala.collection.TraversableLike$$anonfun$map$.apply(TraversableLike.scala:)
at scala.collection.TraversableLike$$anonfun$map$.apply(TraversableLike.scala:)
at scala.collection.mutable.ResizableArray$class.foreach(ResizableArray.scala:)
at scala.collection.mutable.ArrayBuffer.foreach(ArrayBuffer.scala:)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:)
at scala.collection.AbstractTraversable.map(Traversable.scala:)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:)
at org.json4s.Extraction$$anonfun$extract$.apply(Extraction.scala:)
at org.json4s.Extraction$$anonfun$extract$.apply(Extraction.scala:)
at org.json4s.Extraction$.customOrElse(Extraction.scala:)
at org.json4s.Extraction$.extract(Extraction.scala:)
at org.json4s.Extraction$.extract(Extraction.scala:)
at com.iteblog.Test$.main(Test.scala:)
at com.iteblog.Test.main(Test.scala)
Caused by: org.json4s.package$MappingException: Parsed JSON values do not match with class constructor
args=
arg types=
executable=Executable(Constructor(public java.sql.Date(int,int,int)))
cause=wrong number of arguments
types comparison result=MISSING(int),MISSING(int),MISSING(int)
at org.json4s.reflect.package$.fail(package.scala:)
at org.json4s.Extraction$ClassInstanceBuilder.instantiate(Extraction.scala:)
at org.json4s.Extraction$ClassInstanceBuilder.result(Extraction.scala:)
at org.json4s.Extraction$$anonfun$extract$.apply(Extraction.scala:)
at org.json4s.Extraction$$anonfun$extract$.apply(Extraction.scala:)
at org.json4s.Extraction$.customOrElse(Extraction.scala:)
at org.json4s.Extraction$.extract(Extraction.scala:)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$buildCtorArg(Extraction.scala:)
... more

可以看出,出现无法解析出 birthday 字段,因为 json4s 并没有提供将字符串解析到 java.sql.Date。那怎么办呢?json4s 为我们提供了自定义解析类型的方法,那就是 CustomSerializer,我们只需要继承这个类,并实现对自定义类型的序列化和反序列化的方法即可。那对我们的例子可以实现如下:

package com.iteblog

import java.sql.Date

import org.json4s.JsonAST.{JNull, JString}
import org.json4s.{CustomSerializer, DefaultFormats, Extraction, Formats}
import org.json4s.jackson.JsonMethods.render
import org.json4s.jackson.JsonMethods.pretty
import org.json4s.jackson.JsonMethods.parse object Iteblog { case class Person(name: String, age: Int, birthday: Date) case object DateSerializer extends CustomSerializer[Date](_ => ( {
case JString(s) => Date.valueOf(s)
case JNull => null
}, {
case d: Date => JString(d.toString)
})) def main(args: Array[String]): Unit = { implicit val formats: Formats = DefaultFormats + DateSerializer val person = Person("iteblog", , Date.valueOf("2019-07-01"))
val jvalue = Extraction.decompose(person) println(pretty(render(jvalue))) val jvalue1 = parse("""{"name" : "iteblog", "age" : 110, "birthday" : "--"}""")
val r = Extraction.extract[Person](jvalue1)
println(r)
}
}

输出

{
"name" : "iteblog",
"age" : ,
"birthday" : "2019-07-01"
}
Person(iteblog,,--)

可见,通过自定义的 DateSerializer 我们可以解析 java.sql.Date 类型了。

在 json4s 中自定义CustomSerializer的更多相关文章

  1. Html中自定义鼠标的形状

    Html中自定义鼠标的形状 <html> <head> <title>自定义的鼠标形状</title> <meta http-equiv=&quo ...

  2. 教你一招:在PowerPoint中自定义可输入文本的占位符

    日常生活中,当我们设计多媒体课件时,默认的版式其实已经够用了.但是,很多时候,我们需要更加个性一点,所以,我们需要自定义很多东西.本文介绍在PowerPoint中自定义可输入文本的占位符. 一.占位符 ...

  3. android代码优化----ListView中自定义adapter的封装(ListView的模板写法)

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  4. 在Eclipse中自定义类似syso的快捷代码模板

    sysout/syso syserr/ syse 点击菜单栏的“Window”->“Preferences”,打开“Preferences”对话框.在Preferences”对话框中点击“Jav ...

  5. 在.net桌面程序中自定义鼠标光标

    有的时候,一个自定义的鼠标光标能给你的程序增色不少.本文这里介绍一下如何在.net桌面程序中自定义鼠标光标.由于.net的桌面程序分为WinForm和WPF两种,这里分别介绍一下. WinForm程序 ...

  6. .net中自定义过滤器对Response内容进行处理

    原文:http://www.cnblogs.com/zgqys1980/archive/2008/09/02/1281895.html 代码DEMO:http://files.cnblogs.com/ ...

  7. SharePoint 2013 中自定义WCF服务

    在使用SharePoint2013的时候,如果其他客户端 API 的组合不足,可以通过自定义 Web 服务扩展 SharePoint.默认情况下,SharePoint 2013 不仅支持创建自定义 A ...

  8. 浅析在QtWidget中自定义Model

    Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接 ...

  9. VBA中自定义类和事件的(伪)注册

    想了解一下VBA中自定义类和事件,以及注册事件处理程序的方法. 折腾了大半天,觉得这样的方式实在称不上“注册”,所以加一个“伪”字.纯粹是瞎试,原理也还没有摸透.先留着,有时间再接着摸. 做以下尝试: ...

随机推荐

  1. linux/unix发行清单

    unix http://www.slackware.com/ https://www.freebsd.org/ http://www.netbsd.org/ https://www.opensuse. ...

  2. 线性排序总结(c++实现)

    前面介绍了一些常用的比较排序算法,它们都是通过比较两个元素的大小进行排序,归并排序和堆排序在最坏情况下的复杂度为O(nlgn),可以证明(使用决策树模型),通过比较进行排序,算法的下界为O(nlgn) ...

  3. httprunner学习14-完整的项目结构设计

    前言 一个完整的接口自动化测试项目到底该如何设计?httprunner框架的知识点其实并不多,前面基本上把一些重要的概念都介绍完了. 本篇就是一个总结性的,可以用于实际工作中设计一个接口自动化测试项目 ...

  4. 项目Alpha冲刺随笔集合

    班级:软件工程1916|W 作业:项目Alpha冲刺 团队名称:SkyReach 目标:完成项目Alpha版本 项目Github地址 评审表 团队博客汇总 队员学号 队员姓名 个人博客地址 备注 22 ...

  5. Spring Boot 中的事务管理

    希望能在发生异常的时候被回退,这时候就可以使用事务让它实现回退,做法非常简单,我们只需要在test函数上添加@Transactional注解即可. 使用@Transactional注解来声明一个函数需 ...

  6. 【转】Linux下tcp连接断开后不释放的解决办法

    问题:在开发测试时发现断开与服务器端口后再次连接时拒绝连接. 分析:服务器上查看端口占用情况,假设端口为8888. netstat -anp |grep 8888 发现端口8888端口显示被占用(ip ...

  7. 【Hadoop】新建hadoop用户以及用户组,给予sudo权限(转)

    1.首先新建用户,adduser命令 sudo adduser hadoop passwd hadoop 输入密码之后,一路 y 确定. 2.添加用户组 在创建hadoop用户的同时也创建了hadoo ...

  8. abp radio表单元素 消失了

    框架将原本的元素都隐藏掉了,取而代之的是根据label定义了自己的样式,如下: [type="radio"]:not(:checked)+label {    padding-le ...

  9. (11)树莓派3 有线网卡静态IP设置

    https://www.cnblogs.com/10e-6/p/5778355.html 树莓派设置静态IP地址 首先终端输入: ifconfig 查看树莓派默认分配的动态IP地址. 图 1-4 配置 ...

  10. cogs 944. [東方S3] 藤原妹红

    二次联通门 : cogs 944. [東方S3] 藤原妹红 /* cogs 944. [東方S3] 藤原妹红 最小生成树 + 树形dp 首先对原图跑最下生成树 后建出一棵树 在树上进行dp 先走到叶子 ...