在 json4s 中自定义CustomSerializer
到目前为止,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的更多相关文章
- Html中自定义鼠标的形状
Html中自定义鼠标的形状 <html> <head> <title>自定义的鼠标形状</title> <meta http-equiv=&quo ...
- 教你一招:在PowerPoint中自定义可输入文本的占位符
日常生活中,当我们设计多媒体课件时,默认的版式其实已经够用了.但是,很多时候,我们需要更加个性一点,所以,我们需要自定义很多东西.本文介绍在PowerPoint中自定义可输入文本的占位符. 一.占位符 ...
- android代码优化----ListView中自定义adapter的封装(ListView的模板写法)
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- 在Eclipse中自定义类似syso的快捷代码模板
sysout/syso syserr/ syse 点击菜单栏的“Window”->“Preferences”,打开“Preferences”对话框.在Preferences”对话框中点击“Jav ...
- 在.net桌面程序中自定义鼠标光标
有的时候,一个自定义的鼠标光标能给你的程序增色不少.本文这里介绍一下如何在.net桌面程序中自定义鼠标光标.由于.net的桌面程序分为WinForm和WPF两种,这里分别介绍一下. WinForm程序 ...
- .net中自定义过滤器对Response内容进行处理
原文:http://www.cnblogs.com/zgqys1980/archive/2008/09/02/1281895.html 代码DEMO:http://files.cnblogs.com/ ...
- SharePoint 2013 中自定义WCF服务
在使用SharePoint2013的时候,如果其他客户端 API 的组合不足,可以通过自定义 Web 服务扩展 SharePoint.默认情况下,SharePoint 2013 不仅支持创建自定义 A ...
- 浅析在QtWidget中自定义Model
Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接 ...
- VBA中自定义类和事件的(伪)注册
想了解一下VBA中自定义类和事件,以及注册事件处理程序的方法. 折腾了大半天,觉得这样的方式实在称不上“注册”,所以加一个“伪”字.纯粹是瞎试,原理也还没有摸透.先留着,有时间再接着摸. 做以下尝试: ...
随机推荐
- Springboot 2.1.1.RELEASE 版本 session保存到MySQL里面
1,pom.xml添加依赖: <!-- 数据库session管理 --> <dependency> <groupId>org.springframework.ses ...
- Odoo中的记录集
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10826218.html 一:record set 1:获取记录集 1)在@api.multi修饰器修饰的函数 ...
- SaltStack--项目实战
saltstack项目实战 项目架构规划 后端web服务器使用Nginx+Php作为站点,通过HAproxy做负载均衡,Keepalived做高可用 项目环境准备 说明: 关闭防火墙.selinux. ...
- jenkiins 配置邮件发送(四)
一.默认邮件配置的方法 Jenkins默认的插件只能发送执行失败的job 系统管理-->系统设置-->邮件通知 需要注意的是系统管理员邮箱地址必须要邮箱通知的邮箱一致,否则不会发送成功 在 ...
- Spring Boot 中的事务管理
希望能在发生异常的时候被回退,这时候就可以使用事务让它实现回退,做法非常简单,我们只需要在test函数上添加@Transactional注解即可. 使用@Transactional注解来声明一个函数需 ...
- 20180519模拟赛T2——pretty
[问题描述] 小美今天对于数列很有兴趣.小美打算找出一些漂亮的序列.一个漂亮的序列的限制如下: 长度为 n ,而且数列里只包含 [1,n] 的整数. 要不是不降的序列就是不升的序列. 小美想知道有多少 ...
- docker for windows pull镜像文件的安装位置
结论: 所有放入镜像文件都放在虚拟硬盘文件里面. windows上安装的docker其实本质上还是借助与windows平台的hyper-v技术来创建一个linux虚拟机,你执行的所有命令其实都是在这个 ...
- ES6学习笔记--Object.is()
ES5比较两个值是否相等, 相等运算符(==)和恒等运算符(===).它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0. javascript缺乏一种运算,在所有环境中, ...
- Xcode 创建.a和framework静态库(转)
最近因为项目中的聊天SDK,需要封装成静态库,所以实践了一下创建静态库的步骤,做下记录. 库介绍 库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行.库分静态库和动态库两种.iOS中的静 ...
- luogu_4317: 花神的数论题
花神的数论题 题意描述: 设\(sum(i)\)表示\(i\)的二进制数中\(1\)的个数. 给定一个整数\(N\),求\(\prod_{i=1}^Nsum(i)\). 输入描述: 输入包含一个正整数 ...