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.pswp.cn/news/42699.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42699.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42699.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

arcgis--坐標系

1、arcgis中&#xff0c;投影坐標系的y坐標一定是7位數&#xff0c;X坐標有兩種&#xff1a;6位和8位。 6位&#xff1a;省略帶號&#xff0c;這是中央經線形式的投影坐標&#xff0c;一般投影坐標中會帶CM字樣&#xff1b;8位&#xff1a;包括帶號&#xff0c;一般投影坐標中…

數字化時代,數據倉庫和商業智能BI系統演進的五個階段

數字化在逐漸成熟的同時&#xff0c;社會上也對數字化的性質有了進一步認識。當下&#xff0c;數字化除了前邊提到的將復雜的信息、知識轉化為可以度量的數字、數據&#xff0c;在將其轉化為二進制代碼&#xff0c;引入計算機內部&#xff0c;建立數據模型&#xff0c;統一進行…

一鍵搭訕以及打招呼設置(swift)

項目描述&#xff1a;用戶通過打招呼設置錄制打招呼語音&#xff0c;添加打招呼文字&#xff0c;首頁feed頁面展示sayhi的小動畫&#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;因…

jdbc 使用rewriteBatchedStatements=true后,報錯

jdbc 使用rewriteBatchedStatementstrue后&#xff0c;報錯了 rewriteBatchedStatementstrue解釋 rewriteBatchedStatementstrue是一個配置選項&#xff0c;它影響MySQL JDBC驅動程序的行為。JDBC是Java數據庫連接的標準。當你使用Java程序連接MySQL數據庫時&#xff0c;你需要…

秋招面經——結合各方面試經驗

Mysql mysql事務 共享鎖與排他鎖 共享鎖&#xff1a;允許一個事務去讀一行&#xff0c;阻止其他事務獲得相同數據集的排他鎖。&#xff08;讀都允許讀&#xff0c;但我在讀不允許你去改&#xff09; 排他鎖&#xff1a;允許一個事務去讀一行&#xff0c;阻止其他事務獲得相同…

UVA 10006 埃氏篩法+快速冪

本題目使用費馬定理時&#xff0c;我隨機定義了10個數字&#xff0c;循環用費馬小定理判斷&#xff0c;數組中的值不用和我的相同&#xff0c;隨機即可。 #include <iostream> using namespace std; typedef unsigned long long ll; bool isPrime[65007]; ll a[10]; voi…

【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…

mac os M1 安裝并啟動 postgreSQL 的問題

Homebrew 安裝 postgreSQL brew install postgresql啟動 brew services start postgresql但報錯&#xff1a; uninitialized constant Homebrew::Service::System解決方案 brew doctor按照 brew doctor 中的建議進行操作&#xff0c;如果不行&#xff0c;如下&#xff1a; h…

常用系統命令

重定向 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;具有…