假设使用SBT进行配置:

val json4sJackson = "org.json4s" %% "json4s-jackson" % "{latestVersion}"

解析JSON字符串

scala> import org.json4s._
scala> import org.json4s.jackson.JsonMethods._
scala> parse(""" { "numbers" : [1, 2, 3, 4] } """)
res0: org.json4s.JsonAST.JValue =
      JObject(List((numbers,JArray(List(JInt(1), JInt(2), JInt(3), JInt(4))))))
scala> parse("""{"name":"Toy","price":35.35}""", useBigDecimalForDouble = true)
res1: org.json4s.package.JValue = 
      JObject(List((name,JString(Toy)), (price,JDecimal(35.35))))

生成JSON

有两种方式生成JSON:

  • DoubleMode 将浮点型数据转换成 JDouble ,这种方式下DSL使用:

import org.json4s.JsonDSL._
// or
import org.json4s.JsonDSL.WithDouble._
  • BigDecimalMode 将浮点型数据转换成 JDecimal ,这种方式下DSL使用:

import org.json4s.JsonDSL.WithBigDecimal._

DSL规则

  • 基本数据类型映射到 JSON 的基本数据类型

  • 任何 Seq 类型映射到 JSON 的数组类型

scala> val json = List(1, 2, 3)
scala> compact(render(json))
res0: String = [1,2,3]
  • Tuple2[String, Any] 将生成字段

scala> val json = ("name" -> "joe")
scala> compact(render(json))
res1: String = {"name":"joe"}
scala> val json = ("name" -> "joe") ~ ("age" -> 35)
scala> compact(render(json))
res2: String = {"name":"joe","age":35}
  • 所有取值都是可选的,如果值不存在,则直接剔除掉键值对

scala> val json = ("name" -> "joe") ~ ("age" -> Some(35))
scala> compact(render(json))
res3: String = {"name":"joe","age":35}
scala> val json = ("name" -> "joe") ~ ("age" -> (None: Option[Int]))
scala> compact(render(json))
res4: String = {"name":"joe"}
  • 自定义DSL必须实现下面的隐式转换:

type DslConversion = T => JValue
object JsonExample extends App {
  import org.json4s._
  import org.json4s.JsonDSL._
  import org.json4s.jackson.JsonMethods._
  case class Winner(id: Long, numbers: List[Int])
  case class Lotto(id: Long, winningNumbers: List[Int], winners: List[Winner], drawDate: Option[java.util.Date])
  val winners = List(Winner(23, List(2, 45, 34, 23, 3, 5)), Winner(54, List(52, 3, 12, 11, 18, 22)))
  val lotto = Lotto(5, List(2, 45, 34, 23, 7, 5, 3), winners, None)
  val json =
    ("lotto" ->
      ("lotto-id" -> lotto.id) ~
      ("winning-numbers" -> lotto.winningNumbers) ~
      ("draw-date" -> lotto.drawDate.map(_.toString)) ~
      ("winners" ->
        lotto.winners.map { w =>
          (("winner-id" -> w.id) ~
           ("numbers" -> w.numbers))}))
  println(compact(render(json)))
 

输出结果为:

scala> JsonExample
{"lotto":{"lotto-id":5,"winning-numbers":[2,45,34,23,7,5,3],"winners":
[{"winner-id":23,"numbers":[2,45,34,23,3,5]},{"winner-id":54,"numbers":[52,3,12,11,18,22]}]}}

使用pretty可以美化输出,注意生成的字符串中没有draw-date字段:

scala> pretty(render(JsonExample.json))
  "lotto":{
    "lotto-id":5,
    "winning-numbers":[2,45,34,23,7,5,3],
    "winners":[{
      "winner-id":23,
      "numbers":[2,45,34,23,3,5]
      "winner-id":54,
      "numbers":[52,3,12,11,18,22]
 

合并与比较

两个JSON对象之间还可以进行合并与比较:

scala> import org.json4s._
scala> import org.json4s.jackson.JsonMethods._
scala> val lotto1 = parse("""{
         "lotto":{
           "lotto-id":5,
           "winning-numbers":[2,45,34,23,7,5,3]
           "winners":[{
             "winner-id":23,
             "numbers":[2,45,34,23,3,5]
       }""")
scala> val lotto2 = parse("""{
         "lotto":{
           "winners":[{
             "winner-id":54,
             "numbers":[52,3,12,11,18,22]
       }""")
scala> val mergedLotto = lotto1 merge lotto2
scala> pretty(render(mergedLotto))
res0: String =
  "lotto":{
    "lotto-id":5,
    "winning-numbers":[2,45,34,23,7,5,3],
    "winners":[{
      "winner-id":23,
      "numbers":[2,45,34,23,3,5]
      "winner-id":54,
      "numbers":[52,3,12,11,18,22]
scala> val Diff(changed, added, deleted) = mergedLotto diff lotto1
changed: org.json4s.JsonAST.JValue = JNothing
added: org.json4s.JsonAST.JValue = JNothing
deleted: org.json4s.JsonAST.JValue = JObject(List((lotto,JObject(List(JField(winners,
JArray(List(JObject(List((winner-id,JInt(54)), (numbers,JArray(
List(JInt(52), JInt(3), JInt(12), JInt(11), JInt(18), JInt(22))))))))))))))

查询JSON

LINQ(继承语言查询)模式

JSON中的值可以通过for生成表达式来提取。

scala> import org.json4s._
scala> import org.json4s.native.JsonMethods._
scala> val json = parse("""
         { "name": "joe",
           "children": [
               "name": "Mary",
               "age": 5
               "name": "Mazy",
               "age": 3
scala> for {
         JObject(child) <- json
         JField("age", JInt(age))  <- child
       } yield age
res0: List[BigInt] = List(5, 3)
scala> for {
         JObject(child) <- json
         JField("name", JString(name)) <- child
         JField("age", JInt(age)) <- child
         if age > 4
       } yield (name, age)
res1: List[(String, BigInt)] = List((Mary,5))

XPATH + HOFs

JSON AST还支持像XPath一样进行查询:

The example json is:
  "person": {
    "name": "Joe",
    "age": 35,
    "spouse": {
      "person": {
        "name": "Marilyn"
        "age": 33
Translated to DSL syntax:
scala> import org.json4s._
scala> import org.json4s.native.JsonMethods._
scala> import org.json4s.jackson.JsonMethods._
scala> import org.json4s.JsonDSL._
scala> val json =
  ("person" ->
    ("name" -> "Joe") ~
    ("age" -> 35) ~
    ("spouse" ->
      ("person" ->
        ("name" -> "Marilyn") ~
        ("age" -> 33)
scala> json \\ "spouse"
res0: org.json4s.JsonAST.JValue = JObject(List(
      (person,JObject(List((name,JString(Marilyn)), (age,JInt(33)))))))
scala> compact(render(res0))
res1: String = {"person":{"name":"Marilyn","age":33}}
scala> compact(render(json \\ "name"))
res2: String = {"name":"Joe","name":"Marilyn"}
scala> compact(render((json removeField { _ == JField("name", JString("Marilyn")) }) \\ "name"))
res3: String = {"name":"Joe"}
scala> compact(render(json \ "person" \ "name"))
res4: String = "Joe"
scala> compact(render(json \ "person" \ "spouse" \ "person" \ "name"))
res5: String = "Marilyn"
scala> json findField {
         case JField("name", _) => true
         case _ => false
res6: Option[org.json4s.JsonAST.JValue] = Some((name,JString(Joe)))
scala> json filterField {
         case JField("name", _) => true
         case _ => false
res7: List[org.json4s.JsonAST.JField] = List(JField(name,JString(Joe)), JField(name,JString(Marilyn)))
scala> json transformField {
         case JField("name", JString(s)) => ("NAME", JString(s.toUpperCase))
res8: org.json4s.JsonAST.JValue = JObject(List((person,JObject(List(
(NAME,JString(JOE)), (age,JInt(35)), (spouse,JObject(List(
(person,JObject(List((NAME,JString(MARILYN)), (age,JInt(33)))))))))))))
scala> json.values
res8: scala.collection.immutable.Map[String,Any] = Map(person -> Map(name -> Joe, age -> 35, spouse -> Map(person -> Map(name -> Marilyn, age -> 33))))

数组元素可以通过索引获取,还可以获取指定类型的元素:

scala> val json = parse("""
         { "name": "joe",
           "children": [
               "name": "Mary",
               "age": 5
               "name": "Mazy",
               "age": 3
scala> (json \ "children")(0)
res0: org.json4s.JsonAST.JValue = JObject(List((name,JString(Mary)), (age,JInt(5))))
scala> (json \ "children")(1) \ "name"
res1: org.json4s.JsonAST.JValue = JString(Mazy)
scala> json \\ classOf[JInt]
res2: List[org.json4s.JsonAST.JInt#Values] = List(5, 3)
scala> json \ "children" \\ classOf[JString]
res3: List[org.json4s.JsonAST.JString#Values] = List(Mary, Mazy)

样式类也可以用来从JSON对象中提取值:

scala> import org.json4s._
scala> import org.json4s.jackson.JsonMethods._
scala> implicit val formats = DefaultFormats // Brings in default date formats etc.
scala> case class Child(name: String, age: Int, birthdate: Option[java.util.Date])
scala> case class Address(street: String, city: String)
scala> case class Person(name: String, address: Address, children: List[Child])
scala> val json = parse("""
         { "name": "joe",
           "address": {
             "street": "Bulevard",
             "city": "Helsinki"
           "children": [
               "name": "Mary",
               "age": 5,
               "birthdate": "2004-09-04T18:06:22Z"
               "name": "Mazy",
               "age": 3
scala> json.extract[Person]
res0: Person = Person(joe,Address(Bulevard,Helsinki),List(Child(Mary,5,Some(Sat Sep 04 18:06:22 EEST 2004)), Child(Mazy,3,None)))

默认情况下构造器参数必须与json的字段匹配,如果json中的字段名在scala不合法,可以这样解决:

  • 使用反引号

scala> case class Person(`first-name`: String)
  • 使用transform转换函数

scala> case class Person(firstname: String)
scala> json transformField {
         case ("first-name", x) => ("firstname", x)
 

如果样式类具有辅助构造函数,提取函数会尽量匹配最佳的构造函数:

scala> case class Bike(make: String, price: Int) {
         def this(price: Int) = this("Trek", price)
scala> parse(""" {"price":350} """).extract[Bike]
res0: Bike = Bike(Trek,350)

Scala基本类型的值可以直接从JSON中提取:

scala> (json \ "name").extract[String]
res0: String = "joe"
scala> ((json \ "children")(0) \ "birthdate").extract[Date]
res1: java.util.Date = Sat Sep 04 21:06:22 EEST 2004

日期格式可以通过重写DefaultFormats方法实现:

scala> implicit val formats = new DefaultFormats {
         override def dateFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
 

JSON对象也可以转换成Map[String, _],每个字段将转换成键值对:

scala> val json = parse("""
           "name": "joe",
           "addresses": {
             "address1": {
               "street": "Bulevard",
               "city": "Helsinki"
             "address2": {
               "street": "Soho",
               "city": "London"
         }""")
scala> case class PersonWithAddresses(name: String, addresses: Map[String, Address])
scala> json.extract[PersonWithAddresses]
res0: PersonWithAddresses("joe", Map("address1" -> Address("Bulevard", "Helsinki"),
                                     "address2" -> Address("Soho", "London")))

样式类可以序列化和反序列化:

scala> import org.json4s._
scala> import org.json4s.jackson.Serialization
scala> import org.json4s.jackson.Serialization.{read, write}
scala> implicit val formats = Serialization.formats(NoTypeHints)
scala> val ser = write(Child("Mary", 5, None))
scala> read[Child](ser)
res1: Child = Child(Mary,5,None)

序列化支持:

  • 任意深度的样式类

  • 所有的基本类型,包括BigInt与Symbol

  • List,Seq,Array,Set以及Map

  • scala.Option

  • java.util.Date

  • Polymorphic Lists

  • 递归类型

  • 只含可序列化字段的类

  • 自定义序列化函数

赠送jar包:json4s-jackson_2.12-3.5.3.jar; 赠送原API文档:json4s-jackson_2.12-3.5.3-javadoc.jar; 赠送源代码:json4s-jackson_2.12-3.5.3-sources.jar; 赠送Maven依赖信息文件:json4s-jackson_2.12-3.5.3.pom; 包含翻译后的API文档:json4s-jackson_2.12-3.5.3-javadoc-API文档-中文(简体)版.zip; Maven坐标:org.json4s:json4s-jackson_2.12:3.5.3; 标签:json4s、jackson、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心使用。 文章目录0 背景1 数据准备(读入数据)2 解析json文件3 组装json4 json写入到文件4.1 直接写入4.2 格式化json字符串后写入4 使用json4s 因为项目项目需要实现修改json数据后重新写入,原本解析json使用的json4sScala3貌似可以去使用circe-json),但是要实现替换json中的值然后重新写回到文件中实现起来方便(没有找到相对应的借口),于是去寻找了一个相对易用的包。找到了org.json,于是就用此包实现了相对应的功能。 1 数据准备(读入数据) import com.sm.common.utils.DateUtil import org.apache.commons.lang3.StringUtils import org.json4s._ import org.json4s.jackson.JsonMethods._ import org.json4s.jackson.Serialization import org.json4s.jackson.Serializa. Json4s 全称就是Json For Scala,为Scala而生 首先上Maven依赖配置,其实Spark中自带了Json4s如果是编写Spark代码,并不需要单独引用Json4s的依赖了 <dependency> <groupId>org.json4s</groupId> <artifactId>json4s-jack... At this moment there are at least 6 json libraries for scala, not counting the java json libraries. All these libraries <groupId>org.json4s</groupId> <artifactId>json4s-jackson_2.10</artifactId> <version>3.2.11</version> </dependency> 构造JSON字符串 例1implicit val f 使用 json4s库 val json4sNative = &quot;org.json4s&quot; %% &quot;json4s-native&quot; % &quot;3.2.11&quot; 数据类型: sealed abstract class JValue case object JNothing extends JValue // 'zero'.. import org.json4s._ import org.json4s.jackson.JsonMethods._ import org.json4s.JsonDSL._ val json = ("name" -> "zhangxing") ~ ("age" -> 35) println(json.obj.toMap.get("ag import org.json4s._ import org.json4s.JsonDSL._ import org.json4s.jackson.JsonMethods._ import org.json4s.jackson.Seria //val parseJson: JValue = parse( """{"name":"Toy","price":35.35}""", useBigDecimalForDouble = true) val parseJson: JValue = parse( """{"name":"Toy","price":35.35}""") // 方法一:JString模式匹配方式 val JString(name) = (parseJson \ "name") println(name) //方法二:extra