到目前为止,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命令head

    1.命令简介 head (head) 用来显示档案的开头至标准输出中.如果指定了多于一个文件,在每一段输出前会给出文件名作为文件头.如果不指定文件,或者文件为"-",则从标准输入读 ...

  2. Java面向对象 练习(类、对象、方法)

    知识点:构造方法.继承.方法重载.方法重写 一. 定义一个点(Point)类,用来表示三维空间中的点(有三个坐标),要求如下: 1.可以生成具有特定坐标的点对象(构造方法): 2.提供可以设置三个坐标 ...

  3. dfs --path sum 问题 本质上就是组合问题(有去重)

    135. 数字组合 中文 English 给定一个候选数字的集合 candidates 和一个目标值 target. 找到 candidates 中所有的和为 target 的组合. 在同一个组合中, ...

  4. maven 下载 jar 包速度慢时,可以自己手动下载 jar 包,然后粘贴到 External Libraries 中

    maven 下载 jar 包速度慢时,可以自己手动下载 jar 包,然后粘贴到 External Libraries 中

  5. python 的 lambda使用笔记

    无参数匿名函数: f=lambda: none f() 输出:none 带参数匿名函数: 带一个参数: f=lambda x:x+1 f(1) 输出:2 带多个参数: f=lambda a,b,c:a ...

  6. 关于springboot项目的jar和war两种打包方式部署的区别

    关于springboot项目的jar和war两种打包方式部署的区别 关于springboot项目的jar和war两种打包方式部署的区别? https://bbs.csdn.net/topics/392 ...

  7. abp radio表单元素 消失了

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

  8. Python列表生成式练习

    ''' 如果list中既包含字符串,又包含整数,由于非字符串类型没有lower()方法,所以列表生成式会报错 使用内建的isinstance函数可以判断一个变量是不是字符串: 返回True 或 Fal ...

  9. linux学习10 Linux目录结构和根文件系统全面讲解

    一.回顾 1.如何获取使用帮助 help,--help,man,info 官方文档,自带文档(README,CHANGELOG,INSTALL),官方文档 发行版的文档 Google Linux Ke ...

  10. SecureCRT 日记保存带时间戳

    %h:%m:%s:%t--- result: