一、json简介
What?
json是一种数据格式,格式灵感来源于JavaScript,作为开发中重要的数据交换格式,它有着几大特点:
- 轻量级的文本数据交换格式。
- 具有自我描述性,易理解。
- 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
- JSON可通过网络进行传输。
语法格式:
JSON结构: 对象{}
,数组[]
对象表示:{key:value, key: value, ...}
示例:
{
"name": "Eliza白",
"hight": 1.8,
"really": false
}
很好理解,键值和另一个键值间要有逗号隔开。上面这个例子就是一个对象。
这个对象中包含三个属性name、hight和really, 其值分别是"Eliza白"字符串和1.8这个number和false这个boolean
数组表示:{value, value, ...}
示例:
["Elizabeth", "Elizabai", "Eliza白"]
同我们的编程语言一样,json对象和包含数组,数组可包含对象。
示例:
{
"Array": [{
"Elizabeth": 1.8
}, {
"Elizabai": 1.9
}, {
"Eliza白": 2.0
}]
}
二、java中的json解析
因为json使用了JavaScript语法,虽然JavaScript能很简单的处理json,但java就不一样了,就需要解析成java对象才能使用。我就记一下几种解析方式吧:
- JSONObject
- GSON
- FastJSON
- JackJSON
以这个json数据为例:
{
"name": "Eliza白",
"height": 1.8,
"carList": [{
"id": 1,
"brand": "爱玛",
"name": "爱玛电动车"
}, {
"id": 2,
"brand": "东风",
"name": "东风汽车"
}]
}
JSONObject:
生成json
直接构建:
fun jsonObject(view: View) {
val car1 = JSONObject()
car1.put("id", 1)
car1.put("brand", "爱玛")
car1.put("name", "艾玛电动车")
val car2 = JSONObject()
car2.put("id", 1)
car2.put("brand", "东风")
car2.put("name", "东风汽车")
val carList = JSONArray()
carList.put(car1)
carList.put(car2)
val people = JSONObject()
people.put("name", "Elizabeth")
people.put("height", 1.8f)
people.put("carList", carList)
Log.i("print", people.toString())
}
print: {"name":"Elizabeth","height":1.8,"carList":[{"id":1,"brand":"爱玛","name":"艾玛电动车"},{"id":1,"brand":"东风","name":"东风汽车"}]}
用Map构建:
fun jsonObject(view: View) {
val hashMap = HashMap<String, Any>()
val car1 = JSONObject()
car1.put("id", 1)
car1.put("brand", "爱玛")
car1.put("name", "艾玛电动车")
val car2 = JSONObject()
car2.put("id", 1)
car2.put("brand", "东风")
car2.put("name", "东风汽车")
val carList = ArrayList<JSONObject>()
carList.add(car1)
carList.add(car2)
hashMap.put("name", "Elizabeth")
hashMap.put("height", 1.8f)
hashMap.put("carList", carList)
val people = JSONObject(hashMap.toString())
Log.i("print", people.toString())
}
解析:
fun jsonObject(view: View) {
val file = File(""+cacheDir+"/myjson.json")
val fileInputStream = FileInputStream(file)
val bufferedReader = BufferedReader(InputStreamReader(fileInputStream))
val stringBuilder = StringBuilder()
try {
while (true){
var line = bufferedReader.readLine()
if (line == null) break
stringBuilder.append(line)
}
}finally {
bufferedReader.close()
}
val json = stringBuilder.toString()
val people = JSONObject(json)
val carList = people.getJSONArray("carList")
Log.i("print", "peopleName: "+people.getString("name"))
Log.i("print", "peopleHeight: "+people.getDouble("height"))
for (i in 0 until carList.length()){
val car = carList.get(i) as JSONObject
Log.i("print", "carName: "+ car.getInt("id"))
Log.i("print", "carName: "+ car.getString("brand"))
Log.i("print", "carName: "+ car.getString("name"))
}
}
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: peopleName: Eliza白
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: peopleHeight: 1.8
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: carName: 1
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: carName: 爱玛
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: carName: 爱玛电动车
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: carName: 2
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: carName: 东风
04-11 22:39:20.006 8246-8246/com.example.actiondispatch I/print: carName: 东风汽车
javabean方式,由于android自带的不能用,我想搞,添加依赖弄了半天,也没积分下载别人的,以后补吧。
下面只讲java对象与json转换,字符串转换就不写了。
GSON
添加依赖
implementation 'com.google.code.gson:gson:2.8.6'
几个注意地方:
- 推荐把成员变量都声明成private
- 被@Transient注解的字段不会被序列化和反序列化
- 如果字段值为null,不参与序列化
- 反序列化时如果某个字段找不到对应值,会赋值为null
- 内部类不会被序列化和反序列化
常用注解:
- @SerializedName(“ID”)
示例:
@SerializedName("User_Name")
var name
{“User_Name”, “Elizabeth”}就可以解析到这个字段,序列化时也会转换成User_Name。
同时还可以指定更多的名字:
@SerializedName(value = "User_Name", alternate = {"Username", "UserName"})
- @Expose(serialize = false, deserialize = false)
表示指定字段能够序列化和反序列化
同时需要通过builder开启生效:
开启后也需要在需要序列化或反序列化的字段上使用该注解标明。
val builder = GsonBuilder()
builder.excludeFieldsWithoutExposeAnnotation()
val json:String = builder.create().toJson(people)
- @Since(1.0) 高于1.0版本可用
- @Until(1.0) 低于1.0版本可用
同时需要用builder开启
builder.setVersion(2.0)
- @JsonAdapter(MyTypeAdapter.class)
注解到javabean上,参数是继承了TypeAdapter的类.class,这样就不用GsonBuilder.registerTypeAdapter(MyTypeAdapter.class)
了
JavaBean:
data class People(var name: String, var height: Float, var carList: ArrayList<Car>)
data class Car(var id: Int, var brand: String, var name: String)
java对象生成json:
fun jsonObject(view: View) {
val carList = ArrayList<Car>()
carList.add(Car(1, "爱玛", "爱玛电动车"))
carList.add(Car(2, "东方", "东风汽车"))
val people = People("Elizabeth", 1.8f, carList)
val json = Gson().toJson(people)
Log.i("print", json)
}
print: {"carList":[{"brand":"爱玛","id":1,"name":"爱玛电动车"},{"brand":"东方","id":2,"name":"东风汽车"}],"height":1.8,"name":"Elizabeth"}
解析:
fun jsonObject(view: View) {
val file = File(""+cacheDir+"/myjson.json")
val fileInputStream = FileInputStream(file)
val bufferedReader = BufferedReader(InputStreamReader(fileInputStream))
val stringBuilder = StringBuilder()
try {
while (true){
var line = bufferedReader.readLine()
if (line == null) break
stringBuilder.append(line)
}
}finally {
bufferedReader.close()
}
val json = stringBuilder.toString()
val fromJson = Gson().fromJson(json, People::class.java)
Log.i("print", fromJson.toString())
}
当然根据需要我们还可用GsonBuilder进行以上序列化和反序列化
TypeAdapter的使用
TypeAdapter用来处理格式问题
修改下json:
{"name": "Eliza白","height": 1.8,"carList": [{"id": null,"brand": "爱玛","name": "爱玛电动车"}, {"id": 2,"brand": "东风","name": "东风汽车"}]}
我们把其中一个id值改为了null
直接用gson解析出来:
People(name=Eliza白, height=1.8, carList=[Car(id=0, brand=爱玛, name=爱玛电动车), Car(id=2, brand=东风, name=东风汽车)])
id变成了0
我们可以利用自定义TypeAdapter转换:
class MyTypeAdapter : TypeAdapter<Int>() {
override fun write(out: JsonWriter?, value: Int?) {
if (value == null){
out?.value(-1)
}else{
out?.value(value)
}
}
override fun read(input: JsonReader?): Int {
if (input?.peek() == com.google.gson.stream.JsonToken.NULL){
input?.nextNull()
return -1;
}else {
return input?.nextInt()!!
}
}
}
继承TypeAdapter并实现两个方法,一个用来序列化,一个用来反序列化
使用:
val json = stringBuilder.toString()
val gson = GsonBuilder().registerTypeAdapter(Int::class.java, MyTypeAdapter())
val people = gson.create().fromJson<People>(json, People::class.java)
结果:
People(name=Eliza白, height=1.8, carList=[Car(id=-1, brand=爱玛, name=爱玛电动车), Car(id=2, brand=东风, name=东风汽车)])
JsonSerializer 和JsonDeserializer
TypeAdapter精简版
只接管序列化的过程就用 JsonSerializer ,只接管反序列化的过程就用 JsonDeserializer.
TypeToken的使用
解决泛型问题
我们改下我们的JavaBean:
data class People<T>(var name: String, var height: Float, var carList: ArrayList<Car<T>>?)
data class Car<T>(var id: T, var brand: String, var name: String)
Gson解析时无法知道T要转成上面类型,这时候就需要TypeToken了
fun jsonObject(view: View) {
val file = File(""+cacheDir+"/myjson.json")
val fileInputStream = FileInputStream(file)
val bufferedReader = BufferedReader(InputStreamReader(fileInputStream))
val stringBuilder = StringBuilder()
try {
while (true){
var line = bufferedReader.readLine()
if (line == null) break
stringBuilder.append(line)
}
}finally {
bufferedReader.close()
}
val json = stringBuilder.toString()
val type: Type? = object : TypeToken<People<String>>() {}.type
val gson =
GsonBuilder()
//.registerTypeAdapter(Int::class.java, MyTypeAdapter())
val people = gson.create().fromJson<People<String>>(json, type)
Log.i("print", people.toString())
Log.i("print", people.carList?.get(0)?.id)
}
满足大家好奇心
json看一下:
{"name": "Eliza白","height": 1.8,"carList": [{"id": 1,"brand": "爱玛","name": "爱玛电动车"}, {"id": 2,"brand": "东风","name": "东风汽车"}]}
输出看一下:
04-12 16:58:52.173 13612-13612/com.example.actiondispatch I/print: People(name=Eliza白, height=1.8, carList=[Car(id=1, brand=爱玛, name=爱玛电动车), Car(id=2, brand=东风, name=东风汽车)])
04-12 16:58:52.174 13612-13612/com.example.actiondispatch I/print: 1
FastJSON:
依赖
implementation 'com.alibaba:fastjson:1.2.68'
序列化:
fun jsonObject(view: View) {
val carList:ArrayList<Car> = ArrayList<Car>()
carList.add(Car(1, "爱玛", "爱玛电动车"))
carList.add(Car(2, "东方", "东风汽车"))
val people = People("Elizabeth", 1.8f, carList)
val json = JSON.toJSONString(people)
Log.i("print",json)
}
反序列化
由于FastJson需要个默认无参构造参数所以我们改下javabean:
class People{
var name: String = ""
var height: Float = -1f
var carList: ArrayList<Car>? = null
constructor()
override fun toString(): String {
return "People(name='$name', height=$height, carList=$carList)"
}
}
class Car {
var id: Int = 0
var brand: String = ""
var name: String = ""
constructor ()
override fun toString(): String {
return "Car(id=$id, brand='$brand', name='$name')"
}
}
fun jsonObject(view: View) {
val file = File(""+cacheDir+"/myjson.json")
val fileInputStream = FileInputStream(file)
val bufferedReader = BufferedReader(InputStreamReader(fileInputStream))
val stringBuilder = StringBuilder()
try {
while (true){
var line = bufferedReader.readLine()
if (line == null) break
stringBuilder.append(line)
}
}finally {
bufferedReader.close()
}
val json = stringBuilder.toString()
val fastJson = JSON.parseObject(json, People::class.java)
Log.i("print",fastJson.toString())
}
泛型:
package com.example.actiondispatch
class People<T>{
var name: String = ""
var height: Float = -1f
var carList: ArrayList<Car<T>>? = null
constructor()
override fun toString(): String {
return "People(name='$name', height=$height, carList=$carList)"
}
}
class Car<T> {
var id: T? = null
var brand: String = ""
var name: String = ""
constructor ()
override fun toString(): String {
return "Car(id=$id, brand='$brand', name='$name')"
}
}
只需修改:
val fastJson = JSON.parseObject(json, object: TypeReference<People<String>>(){})
JackJSON:
依赖
implementation 'com.fasterxml.jackson.core:jackson-databind:2.11.0.rc1'
implementation 'com.fasterxml.jackson.core:jackson-core:2.11.0.rc1'
implementation 'com.fasterxml.jackson.core:jackson-annotations:2.11.0.rc1'
常见注解
@JsonIgnore 注解的字段将不会进行序列化
@JsonFormat(pattern = " ")格式化
序列化:
fun jsonObject(view: View) {
val objectMapper = ObjectMapper()
val carList:ArrayList<Car> = ArrayList<Car>()
carList.add(Car(1, "爱玛", "爱玛电动车"))
carList.add(Car(2, "东方", "东风汽车"))
val people = People("Elizabeth", 1.8f, carList)
val json = objectMapper.writeValueAsString(people);
Log.i("print",json)
}
反序列化:
(同样javabean也要无参构造)
fun jsonObject(view: View) {
val file = File(""+cacheDir+"/myjson.json")
val fileInputStream = FileInputStream(file)
val bufferedReader = BufferedReader(InputStreamReader(fileInputStream))
val stringBuilder = StringBuilder()
try {
while (true){
var line = bufferedReader.readLine()
if (line == null) break
stringBuilder.append(line)
}
}finally {
bufferedReader.close()
}
val json = stringBuilder.toString()
val objectMapper = ObjectMapper()
val readValue = objectMapper.readValue(json, object: com.fasterxml.jackson.core.type.TypeReference<People<String>>(){})
Log.i("print",readValue.toString())
}