scala中json4s 使用详解

预备知识

json4s的数据结构AST (Abstract Syntax Tree)。

sealed abstract class JValue
case object JNothing extends JValue // 'zero' for JValue
case object JNull extends JValue
case class JString(s: String) extends JValue
case class JDouble(num: Double) extends JValue
case class JDecimal(num: BigDecimal) extends JValue
case class JInt(num: BigInt) extends JValue
case class JBool(value: Boolean) extends JValue
case class JObject(obj: List[JField]) extends JValue
case class JArray(arr: List[JValue]) extends JValuetype JField = (String, JValue)

我们可以通过 json4s 对json所做的操作如下图所示,中间为 Json AST (简单理解就是一个用JValue表示的 JSON)。
在这里插入图片描述

另外,org.json4s下定义了很多scala原生数据转JValue的隐式转换(即多数操作下可以把原生数据当做JValue直接使用)
在这里插入图片描述
但是注意:Tuple不能自动转为JValue,在需要转换的时候,render先转一下,如:json merge render("height",175)

一、 创建json对象

{"name":"luca", "id": "1q2w3e4r5t", "age": 26, "url":"http://www.nosqlnocry.wordpress.com"}

方式1:parse函数

// parse from string example,得到的是JValue对象
var json = parse("""{"name":"luca", "id": "1q2w3e4r5t", "age": 26, "url":"http://www.nosqlnocry.wordpress.com"}""")

方式2:dsl创建

org.json4s中定义了从tuple到JValue的操作符

// DSL example,是JObject对象
var json = ("name","luca") ~ ("id","1q2w3e4r5t") ~ ("age",26) ~ ("url","http://www.nosqlnocry.wordpress.com")
// tuples can be defined also like this: ("id" -> "1q2w3e4r5t")
println(json)
JObject(List((name,JString(luca)), (id,JString(1q2w3e4r5t)), (age,JInt(26)), (url,JString(http://www.nosqlnocry.wordpress.com))))

二、常用操作

2.1 新增一个field

注意,以下两个方法都不会覆盖,若原json中已有height,则新json中会有两个height.

//法1:使用dsl,JObject才有~方法
json = json ~ ("height" -> 175) 
//法2: 使用merge,要求类型和左边一致,所以json为parse出来的JValue时,要用render生成JValue再merge
json = json merge render("height",175)

2.2 更新一个field

使用 transformField

json = json transformField {case JField("name", _) => ("NAME", JString("Luca")) //还可重命名case JField("age", JInt(age)) => ("age", JInt(age+1))//更新值
}json = json merge render("age",26) //若json 中已有"age"

2.3 删除一个field

json = json removeField {case JField("NAME", _) => true //被删除case _ => false
}
// 或等价的
json = json filterField {case JField("NAME", _) => false case _ => true //被保留}

2.4 获取一个field

println(compact(json \\ "age")) // 27 嵌套获取-见下
println(compact(json \ "age"))  // 27
println(compact(json.children(1))) // 27

三、高阶操作

{"name": "luca","id": "1q2w3e4r5t","age": 26,"url": "http://www.nosqlnocry.wordpress.com","url": "https://nosqlnocry.wordpress.com","loginTimeStamps": [1434904257,1400689856,1396629056],"messages": [{"id": 1,"content": "Please like this post!"},{"id": 2,"content": "Forza Roma!"}],"profile": {"id": "my-nickname","score": 123,"avatar": "path.jpg"}
}

3.1 选取field

println(JSON)
//JObject(List((name,JString(luca)), (id,JString(1q2w3e4r5t)), (age,JInt(26)), (url,JString(http://www.nosqlnocry.wordpress.com)), (url,JString(https://nosqlnocry.wordpress.com)), (loginTimeStamps,JArray(List(JInt(1434904257), JInt(1400689856), JInt(1396629056)))), (messages,JArray(List(JObject(List((id,JInt(1)), (content,JString(Please like this post!)))), JObject(List((id,JInt(2)), (content,JString(Forza Roma!))))))), (profile,JObject(List((id,JString(my-nickname)), (score,JInt(123)), (avatar,JString(path.jpg)))))))println(JSON\\"id") //获取所有嵌套的id数据
// prints: JObject(List((id,JString(1q2w3e4r5t)), (id,JInt(1)), (id,JInt(2)), ...println(JSON\"id")//获取第一层的id数据
// prints: JString(1q2w3e4r5t)println(JSON\"url") //如果第一层有多个,则返回JArray
// prints: JArray(List(JString(http://www...), JString(https://nosqlnocry...val messagesIds = (JSON \ "messages") \ "id" //获取JAray中的id数据
println(messagesIds)
// prints: JArray(List(JInt(1), JInt(2)))
println(messagesIds.values)
// prints: List(1,2)
//或用for语句
val messagesIds2=  for {JObject(child) <- JSONJField("id", JInt(id)) <- child} yield idprintln(messagesIds2)// prints: List(1,2)

for语句的<-在JValue中做了特殊处理,会返回所有匹配项。

    for {JObject(child) <- JSON //这回匹配所有JObject,不管是不是嵌套}{println(child)}
//List((name,JString(luca)), (id,JString(1q2w3e4r5t)), (age,JInt(26)), (url,JString(http://www.nosqlnocry.wordpress.com)), (url,JString(https://nosqlnocry.wordpress.com)), (loginTimeStamps,JArray(List(JInt(1434904257), JInt(1400689856), JInt(1396629056)))), (messages,JArray(List(JObject(List((id,JInt(1)), (content,JString(Please like this post!)))), JObject(List((id,JInt(2)), (content,JString(Forza Roma!))))))), (profile,JObject(List((id,JString(my-nickname)), (score,JInt(123)), (avatar,JString(path.jpg))))))
//List((id,JInt(1)), (content,JString(Please like this post!)))
//List((id,JInt(2)), (content,JString(Forza Roma!)))
//List((id,JString(my-nickname)), (score,JInt(123)), (avatar,JString(path.jpg)))

JValue的<-调用的是

    def foreach(f: JValue => Unit): Unit =self.filter(p).foreach(f)

Array的<-调用的是

  def foreach[U](f: A => U): Unit = {var i = 0val len = lengthwhile (i < len) { f(this(i)); i += 1 }}

3.2 取出field

println(compact(render(JSON \ "messages")))
// prints: [{"id":1,"content":"Please like this post!"},{"id":2,"content":"Forza Roma!"}]
println(pretty(render((JSON \ "messages")\"content")))
// prints: [ "Please like this post!", "Forza Roma!" ] // note it is not compacted anymoreprintln(pretty(render(JSON \ "age")))
// prints: 26println(compact(render(JSON \ "name")))
// prints: "luca" // note the apostrophesvar name = for { JString(x) <- (JSON \\ "name") } yield x //或用for表达式去掉双引号
println(name(0))
// prints: lucavar name = (JSON \ "name") //或用values去掉双引号,保留对应基本类型时,推荐这种方法
println(name.values)
// prints: lucaimplicit val formats = DefaultFormats
val name = (JSON \ "name").extract[String]//或直接extract,已知需要的类型时推荐这种方法
println(name)
// prints: luca

name.values 原理:在这里插入图片描述

3.3 查找和过滤filed

//返回第一个遇到的元素
val URL = JSON findField {
case JField("url", _) => true
case _ => false
}
println(URL)
// prints: Some((url,JString(http://www.nosqlnocry.wordpress.com)))// 返回所有符合条件的元素
val URLs = JSON filterField {
case JField("url", _) => true
case _ => false
}
println(URLs)
// prints: List((url,JString(http://www.nosqlnocry...)), (url,JString(https://nosqlnocry...)

3.4 合并与差异另一个Json2:merge和diff

{"messages": [{"id": 3,"content": "how to merge?"}],"url": "anotherURL","loginTimeStamps": 1400689856,"profile": {"avatar": "new.jpg"},"new": "new value"
}

Json1 merge Json2

  1. 如果字段法Json1/f1与Json2/f1结构不同,或者仅具有简单结构,则Json2会替换Json1的f1
  2. 若结构相同且为复杂结构,则会合并
  3. 若Json2/f1在Json1中不存在,则新增
    在这里插入图片描述
    diff 获取两个JSon间的不同(用得少):
val newUserJSON = """{"name":"luca","id": "anotherID","age": 26,"url":"http://www.nosqlnocry.wordpress.com",               "profile":{"id":"another-nickname", "score":99999, "avatar":"path.jpg"}
}
"""    
val Diff(changed, added, deleted) = JSON diff parse(newUserJSON)println(compact(render(changed)))
println(added)
println(pretty(render(deleted)))
/* print:
{"id":"anotherID","profile":{"id":"another-nickname","score":99999}}
JNothing
{"url" : "https://nosqlnocry.wordpress.com","loginTimeStamps" : [ 1434904257, 1400689856, 1396629056 ],"messages" : [ {"id" : 1,"content" : "Please like this post!"}, {"id" : 2,"content" : "Forza Roma!"} ]
}*/

3.5 类和JSon间的转换:decompose, extract, write和read

case class Item(info: String, rank: Int)
case class Item2(info: String, rank: Int, name:String)
implicit val formats: Formats = DefaultFormatsval vMap=Map("info" -> "abcd", "rank" -> 123, "other" -> "dsf")
val jsonStr = write(vMap)
println(jsonStr)
//{"info":"abcd","rank":123,"other":"dsf"}val json = parse(jsonStr)
println(json)val json2 = Extraction.decompose(vMap)//可以理解为等价于parse(write(vMap))
println(json2)val json=parse(jsonStr)
//val json2=
println(json.extract[Map[String,Any]])
//Map(info -> abcd, rank -> 123, other -> dsf)
println(read[Map[String,Any]](jsonStr))//可理解为和json.extract效果一样,但是跳过了将str转为JValue对象的过程
//Map(info -> abcd, rank -> 123, other -> dsf)println(json.extract[Item])//case class 的字段名要和json的field一致,可少不可多与json有的field
//Item(abcd,123)
println(read[Item](jsonStr))
//Item(abcd,123)println(json.extract[Item2])//不可多于json有的field
//报错,org.json4s.MappingException: No usable value for nameprintln(read[Item2](jsonStr))
//报错,org.json4s.MappingException: No usable value for name

不用默认格式:(非scala基类作为父类的话,默认格式解析会出错)

  trait Animalcase class Dog(name: String) extends Animalcase class Fish(weight: Double) extends Animalcase class Animals(animals: List[Animal])implicit val formats1: Formats = DefaultFormatsval formats2: Formats = Serialization.formats(ShortTypeHints(List(classOf[Dog], classOf[Fish])))implicit val mf = manifest[Animals]val ser1 = write(Animals(Dog("pluto") :: Fish(1.2) :: Nil))(formats1)val ser2 = write(Animals(Dog("pluto") :: Fish(1.2) :: Nil))(formats2)println(ser1)//{"animals":[{"name":"pluto"},{"weight":1.2}]}println(ser2)//{"animals":[{"jsonClass":"BasicTest$Dog","name":"pluto"},{"jsonClass":"BasicTest$Fish","weight":1.2}]}println(read[Animals](ser2)(formats2, mf))//Animals(List(Dog(pluto), Fish(1.2)))println(parse(ser2).extract[Animals](formats2,mf))//Animals(List(Dog(pluto), Fish(1.2)))println( read[Animals](ser2)(formats1,mf))// 报错//org.json4s.MappingException: No usable value for animals,No constructor for type Animal, JObject(List((jsonClass,JString(BasicTest$Dog)), (name,JString(pluto))))println( read[Animals](ser1))//等价于println( read[Animals](ser1)(formats1,mf)) ,报错//org.json4s.MappingException: No usable value for animals No constructor for type Animal, JObject(List((name,JString(pluto))))println(parse(ser1).extract[Animals])//报错//org.json4s.MappingException: No usable value for animals No constructor for type Animal, JObject(List((name,JString(pluto))))println(parse(ser2).extract[Animals])//报错//org.json4s.MappingException: No constructor for type Animal, JObject(List((jsonClass,JString(BasicTest$Dog)), (name,JString(pluto))))

参考

官方教程
WORKING WITH JSON IN SCALA USING THE JSON4S LIBRARY (PART ONE)
WORKING WITH JSON IN SCALA USING THE JSON4S LIBRARY (PART TWO)
Purpose of render in json4s

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/42699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字化时代,数据仓库和商业智能BI系统演进的五个阶段

数字化在逐渐成熟的同时&#xff0c;社会上也对数字化的性质有了进一步认识。当下&#xff0c;数字化除了前边提到的将复杂的信息、知识转化为可以度量的数字、数据&#xff0c;在将其转化为二进制代码&#xff0c;引入计算机内部&#xff0c;建立数据模型&#xff0c;统一进行…

CAS 一些隐藏的知识,您了解吗

目录 ConcurrentHashMap 一定是线程安全的吗 CAS 机制的注意事项 使用java 并行流 &#xff0c;您要留意了 ConcurrentHashMap 在JDK1.8中ConcurrentHashMap 内部使用的是数组加链表加红黑树的结构&#xff0c;通过CASvolatile或synchronized的方式来保证线程安全的,这些原理…

TikTok或将于8月底关闭半闭环、速卖通或将推出“半托管”模式

《出海周报》是运营坛为外贸企业主和外贸人独家打造的重要资讯栏目&#xff0c;聚焦企业出海、海外市场动态、海外监管政策等方面&#xff0c;以简捷的方式&#xff0c;提升读者获取资讯的效率。 接下来运营坛为大家带来第15期出海周报&#xff0c;快来看看这周国内外市场发生了…

C++--红黑树

1.什么是红黑树 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位表示结点的颜色&#xff0c;可以是Red或Black。 通过对任何一条从根到叶子的路径上各个结点着色方式的限制&#xff0c;红黑树确保没有一条路径会比其他路径长出俩倍&#xff0c;因…

【Unity细节】Unity中的层级LayerMask

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

Mybatis Plus中使用LambdaQueryWrapper进行分页以及模糊查询对比传统XML方式进行分页

传统的XML分页以及模糊查询操作 传统的XML方式只能使用limit以及offset进行分页&#xff0c;通过判断name和bindState是否为空&#xff0c;不为空则拼接条件。 List<SanitationCompanyStaff> getSanitationStaffInfo(Param("name") String name,Param("bi…

前端---需要了解浏览器相关知识--浏览器请求服务器资源---缓存

知识点1: 掘金1&#xff1a;浏览器缓存 掘金2 :浏览器缓存 一、浏览器缓存 请求&#xff08;静态资源 &#xff5c; 动态资源&#xff09; 一、缓存是什么&#xff1f; 如果没有缓存的机制 每次都要重新请求静态资源 1.从网络上的下载时间&#xff0c;肯定大于从硬盘里读的…

【S32K 进阶之旅】S32K 芯片的解锁

在使用 S32K1xx MCU 的过程中&#xff0c;因为某些不当操作导致芯片被锁、加密的情况偶有发生&#xff0c;在此总结一篇如何解锁芯片的文档&#xff0c;希望能够帮到有需要的人。 1. S32K 芯片被锁的现象及原因分析1&#xff09;在S32K 系列 MCU 开发和生产过程中&#xff…

常用系统命令

重定向 cat aa.txt > bbb.txt 将输出定向到bbb.txt cat aaa.txt >> bbb.txt 输出并追加查看进程 ps ps -ef 显示所有进程 例⼦&#xff1a;ps -ef | grep mysql |&#xff1a;管道符 kill pid 结束进程&#xff0c; 如 kill 3732&#xff1b;根据进程名结束进程可以先…

Qt使用qml(QtLocation)显示地图

一、qt版本和QtLocation模块版本确认 如果qt版本过低的话是没有QtLocation模块的&#xff0c;我的版本如下 构建工具版本如下 二、qml代码编写 1、工程中添加模块 首先在工程中添加模块quickwidgets positioning location 2、添加资源文件 3、在资源文件中添加qml文件 …

Jenkins改造—nginx配置鉴权

先kill掉8082的端口进程 netstat -natp | grep 8082 kill 10256 1、下载nginx nginx安装 EPEL 仓库中有 Nginx 的安装包。如果你还没有安装过 EPEL&#xff0c;可以通过运行下面的命令来完成安装 sudo yum install epel-release 输入以下命令来安装 Nginx sudo yum inst…

windows上的docker自动化部署到服务器脚本

1、mvn install后&#xff0c;双击这个bat&#xff0c;实现docker build后上传到124服务器&#xff0c;并且重启124服务器 **echo offsetlocal:: 定义镜像名称和版本变量 set IMAGE_NAMEweb set IMAGE_VERSION1.3.1:: 清理本地文件 echo Cleaning up... del service-%IMAGE_N…

中大许少辉博士中国建筑出版传媒八一新书《乡村振兴战略下传统村落文化旅游设计》百度百科新闻

中大许少辉博士中国建筑出版传媒八一新书《乡村振兴战略下传统村落文化旅游设计》百度百科新闻&#xff1a; 乡村振兴战略下传统村落文化旅游设计 - 百度百科 https://baike.baidu.com/item/乡村振兴战略下传统村落文化旅游设计/62588677 概览 《乡村振兴战略下传统村落文化旅游…

c++——静态成员变量、静态成员函数和const修饰的静态成员变量

一、c静态成员变量 在C中&#xff0c;静态成员变量&#xff08;Static Member Variable&#xff09;是类的一种特殊类型的成员变量&#xff0c;它被类的所有实例共享&#xff0c;而不是每个实例都有自己的副本。静态成员变量在类的所有对象之间保持唯一的状态&#xff0c;具有…

Redisson实现分布式锁示例

一、引入依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.16.0</version></dependency>二、配置类 import org.redisson.Redisson; import org.redisson.api.RedissonClient;…

Hadoop学习:深入解析MapReduce的大数据魔力(三)

Hadoop学习&#xff1a;深入解析MapReduce的大数据魔力&#xff08;三&#xff09; 3.5 MapReduce 内核源码解析3.5.1 MapTask 工作机制3.5.2 ReduceTask 工作机制3.5.3 ReduceTask 并行度决定机制 3.6 数据清洗&#xff08;ETL&#xff09;1&#xff09;需求2&#xff09;需求…

Java数据库连接池原理及spring boot使用数据库连接池(HikariCP、Druid)

和线程池类似&#xff0c;数据库连接池的作用是建立一些和数据库的连接供需要连接数据库的业务使用&#xff0c;避免了每次和数据库建立、销毁连接的性能消耗&#xff0c;通过设置连接池参数可以防止建立连接过多导致服务宕机等&#xff0c;以下介绍Java中主要使用的几种数据库…

【学习FreeRTOS】第11章——FreeRTOS中任务相关的其他API函数

1.函数总览 序号函数描述1uxTaskPriorityGet()获取任务优先级2vTaskPrioritySet()设置任务优先级3uxTaskGetNumberOfTasks()获取系统中任务的数量4uxTaskGetSystemState()获取所有任务的状态信息5vTaskGetInfo()获取单个任务的状态信息6xTaskGetCurrentTaskHandle()获取当前任…

Excel自动化办公——Openpyxl的基本使用

Excel自动化办公——Openpyxl的基本使用 个人感觉&#xff0c;相比Pandas&#xff0c;openpyxl对Excel的操作更为细致&#xff0c;Pandas则更适用于统计计算&#xff1b; 01 基本环境02 Excel数据读取操作03 案例04 向Excel写入数据05 表数据定向修改06 单元格样式制定07 单元…

原型对象的简单了解

在前面学习java有一个概念叫做继承&#xff0c;方便我们对父类方法、变量等的调用。对前端的学习我们需要让对象可以访问和继承其他对象的属性和方法&#xff0c;就需要了解原型对象&#xff0c;以及原型链。 一、原型 构造函数通过原型分配的函数是所有对象所共享的。每一个构…