写再前面的总结:
1, 做少量文件解析,优先用json4s,因为json4s时基于Scala开发的,对scala使用场景支持更好
2. 做大量数据的解析,追求序列化、反序列化速度时,考虑用fastjson,但是fastjson是基于java开发的,对scala支持不好。所以,除非遇到性能提升场景或者只是简单的json处理,才考虑在scala中用fastjson。
可选工具:
fastjson
gson
json4s(jackson的scala版本)
lift-json
spray-json
circle
play-json
一、fastjson 简介
一、阿里巴巴FastJson是一个Json处理工具包,包括“序列化”和“反序列化”两部分,它具备如下特征:
速度最快,测试表明,fastjson具有极快的性能,超越任其他的Java Json parser。包括自称最快的JackJson;
功能强大,完全支持Java Bean、集合、Map、日期、Enum,支持范型,支持自省;无依赖;
Json解析工具使用的 json-smart,曾经对比过Java的fastjson、gson。Scala的json4s、lift-json。其中 json-smart 解析速度是最快的。
二、fastjson 使用对比 json4s
json4s官网样例:https://github.com/json4s/json4s
import org.scalatest.funsuite
import org.json4s.jackson.JsonMethods._
import org.json4s._
import org.json4s.JsonDSL._
import scala.collection.{immutable, mutable}
import com.alibaba.fastjson2.JSON
import com.alibaba.fastjson2.JSONWriter
import com.alibaba.fastjson2.JSONReader
class BasicTest extends funsuite.AnyFunSuite {
test("option map 使用") {
val m1 = Map("a" -> 1, "b" -> 2)
val c1 = m1.get("c") //返回Option
val m2 = Some(Map("a" -> 1, "b" -> 2))
val a = m2.get("a") //返回value,key不存在会报错
// val c2=m2.get("c") //返回value,key不存在会报错
val m3 = m2.get //get 不带参数,是取option里面的值
println(m3)
val str: Option[String] = Some("test")
str match {
case Some(x) => x
case None => "NA"
}
str.getOrElse("NA")
}
test("json4s 官网示例1"){
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)))
}
test("json4s官网示例2"){
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]
}]
}
}""")
val lotto2 = parse("""{
"lotto":{
"winners":[{
"winner-id":54,
"numbers":[52,3,12,11,18,22]
}]
}
}""")
val mergedLotto = lotto1 merge lotto2
println(pretty(render(mergedLotto)))
val Diff(changed, added, deleted) = mergedLotto diff lotto1
println(changed, added, deleted)
}
//不能在方法中定义case class
case class Child(name: String, age: Int, birthdate: Option[java.util.Date])
case class Address(street: String, city: String)//提取的字段名要和json中的field一致
case class Address2(street: String, city: String,home:Option[String])//可选字段用Option,否则没有的话会报错
case class Person(name: String, address: Address, children: List[Child])
test("json4s 官网示例3"){
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
}
]
}
""")
implicit val formats: Formats = DefaultFormats
println(json.extract[Person])
val addressJson = json \ "address"
println(addressJson.extract[Address])
println(addressJson.extract[Address2])
println( (json \ "children").extract[List[Child]])
}
test("fastjson对应示例3"){
val jsonStr = """
{ "name": "joe",
"address": {
"street": "Bulevard",
"city": "Helsinki"
},
"children": [
{
"name": "Mary",
"age": 5,
"birthdate": "2004-09-04T18:06:22Z"
},
{
"name": "Mazy",
"age": 3
}
]
}
"""
println(JSON.parseObject(jsonStr,classOf[Person])) //报错
}
test("fastjson") {
val jobJsonStr = """{"name":"Job","age":19,"tasks":[{"name":"a"},{"name":"b"}],"js":{"a2":1,"b2":2}}"""
val fJson = JSON.parseObject(jobJsonStr)
println("\n****fastjson****")
println(fJson.get("name"))
val m2=Map("a"->"1","b"->"2")
import collection.JavaConverters._
println(JSON.toJSONString(m2.asJava, Array[JSONWriter.Feature](): _*))
//println(JSON.parseObject("""{"name":"Job","age":"19"}""",classOf[model]))
println(JSON.parseObject("""{"name":"Job","age":19}""",classOf[java.util.Map[String, String]]).asScala)
//println(JSON.parseObject(jobJsonStr).getObject("js",classOf[java.util.Map[String, String]],Array[JSONReader.Feature](): _*).asScala.mkString(","))//a 会报冲突
// val m=JSON.parseObject("""{"name":"Job","age":"19"}""",classOf[Map[String, String]],JSONReader.Feature.FieldBased)//实现不了。。。类似json4j的那种便捷的变换
val tmpStr=JSON.parseObject(jobJsonStr).getJSONObject("js").toString
println(tmpStr)
println(JSON.parseObject(tmpStr,classOf[java.util.Map[String, String]]).asScala.mkString(","))//a如果报冲突,按理也应该报冲突parseObject(String text, Class<T> clazz) 和 parseObject(String text, Type type)
}
}
要想像json4s那样再scala中用好fastjson是比较难的,因为jastjson都要基于java类做转化,会有不少适配问题:例如。
关于json4s extract的隐式参数:
def extract[A](implicit formats : org.json4s.Formats, mf : scala.reflect.Manifest[A]) : A = { /* compiled code */ }
//formats来源
implicit val formats: Formats = DefaultFormats
//mf来源,scala在运行时会隐式引入如下方法(待验证该描述)
scala.reflect.ManifestFactory.classType
//验证:Json4sTest.scala
object Json4sTest {
def testMf[A](a:A)(implicit mf:scala.reflect.Manifest[A]):A={
println(a.toString)
a
}
def main(args: Array[String]): Unit = {
testMf("abc")
}
}
执行
scalac -Xprint:typer Json4sTest.scala
输出:
Json4sTest.this.testMf[String]("abc")(scala.reflect.ManifestFactory.classType[String](classOf[java.lang.String]));
一定要用fastjson,并且子弟定义解析case class,就没有办法了吗?
有的,使用BeanProperty注解:
import com.alibaba.fastjson.JSON
import scala.beans.BeanProperty
object Class_ttt {
class Person{
var name:String = "zahngsan"
var age :Int = 20
}
class Student(@BeanProperty val name:String,@BeanProperty val age:Int)
/**
* 封装:属性私有,提供共有的set/get方法
*
* scala中提供了一个注解@BeanProperty 能够自动生成java的get/set方法
*
* scala中可以使用java的API,java的很多API都要求有get/set方法,scala为了兼容java提供了@BeanProperty
*
* @BeanProperty注解不能用于private修饰的属性上
*
*
*/
def main(args: Array[String]): Unit = {
val json ="""{"name":"lisi","age":"30"}"""
val student: Student = JSON.parseObject(json,classOf[Student])
println(student.name)
val student2 = new Student("wangwu",23)
println(JSON.toJSON(student2))
}
}
其他参考:
json4s官方教程:https://github.com/json4s/json4s
json4s使用教程:https://www.cnblogs.com/yyy-blog/p/11819302.html
fastjson官方使用指导:https://github.com/alibaba/fastjson/wiki/%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98
fastjson2:https://github.com/alibaba/fastjson2
fastjson 升级 fastjson2:https://github.com/alibaba/fastjson2/wiki/fastjson_1_upgrade_cn
fastjson元素遍历:https://blog.csdn.net/Lzx116/article/details/126974187?ops_request_misc=&request_id=&biz_id=102&utm_term=scala%20fastjson%20getobject&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-126974187.142^v73^pc_search_v2,201^v4^add_ask,239^v2^insert_chatgpt&spm=1018.2226.3001.4187
scala和java的type于class:https://stackoverflow.com/questions/1135248/scala-equivalent-of-java-java-lang-classt-object
Scala中使用JSON.toJSONString报错:ambiguous reference to overloaded definition:https://developer.aliyun.com/article/627434
Scala中使用JSON.toJSONString报错 2:https://stackoverflow.com/questions/6209120/scala-ambiguous-reference-to-overloaded-definition-with-varargs
参考:
https://blog.csdn.net/weixin_44259720/article/details/115111105
https://juejin.cn/post/7090371049442803748
https://www.rokub.com/58902.html
https://blog.csdn.net/chongshan6464/article/details/100866144
https://blog.csdn.net/lvtula/article/details/93387861
https://www.jianshu.com/p/93ffc45c8010
fastjson测试:https://github.com/alibaba/fastjson2/wiki/fastjson_benchmark