Json

Posted by ooftf on April 12, 2021

Problems


  • 如果json中有某个对象不想解析,但是想找个对象去接收,不要使用org.json.JSONObject, 如果使用org.json.JSONObject;在解析的过程中会被忽略掉,不会得到对应的结果。 如果你使用的是fastjson可以使用com.alibaba.fastjson.JSONObject 可以得到想要的结果但是不推荐(FastJson已确认可以) 同理Gson等也要使用对应包下的JSONObject才可以(Gson未确认,处于猜想阶段)
  • 如果json解析过程中出错,fastjson和gson都会立即中断解析,后面字段将不会解析 但是jackjson会跳过出错字段继续解析,最终结果只会缺少出错的字段
  • JavaBean set 和 get 方法都要设置为public

Kotlin

//”{“name”:”lihang”,”desc”:”dashuaibi”}”

1
2
3
4
5
6
7
8
9
data class GsonBean(val name: String, val desc: String) {
}
val gsonString = "{\"desc\":\"dashuaibi\"}"
// 结论:name 字段为null
//使用 deployDefaultValue  name : null


val gString = "{\"name\":null,\"desc\":\"dashuaibi\"}"
//使用 deployDefaultValue  name : ""
1
2
3
4
5
val gsonString = "{\"desc\":\"dashuaibi\"}"
data class GsonBean(val name: String = "lihang", val desc: String) {
}
// name : null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class GsonBean {
    var name: String = "lihang"
    val desc: String = ""
}
val gsonString = "{\"desc\":\"dashuaibi\"}"
// name = lihang
// desc = dashuaibi


val gString = "{\"name\":null,\"desc\":\"dashuaibi\"}"
// name = null
// desc = dashuaibi

//使用 deployDefaultValue  name : ""

结论:

  • 构造方法默认值是没有作用的
  • 在拥有无参构造函数的情况下,成员方法默认值是有作用的,在Json没有该变量的时候会采用默认变量
  • deployDefaultValue只会在Json中为null的时候起作用,如果没有该变量是没有作用的

问题:为什么Gson可以创建(没有无参构造方法的类)的对象

Gson创建(没有无参构造方法的类)的对象的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static UnsafeAllocator create() {
    // 最关键
    try {
     // 反射找到sun.misc.Unsafe类
      Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
      // 找到sun.misc.Unsafe类中的theUnsafe属性
      Field f = unsafeClass.getDeclaredField("theUnsafe");
      // 激活theUnsafe属性
      f.setAccessible(true);
      // 得到theUnsafe的对象
      final Object unsafe = f.get(null);
      // 反射allocateInstance方法
      final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
      return new UnsafeAllocator() {
        @Override
        @SuppressWarnings("unchecked")
        public <T> T newInstance(Class<T> c) throws Exception {
          assertInstantiable(c);
          // 调用allocateInstance方法,创建类型为c的对象
          return (T) allocateInstance.invoke(unsafe, c);
        }
      };
    } catch (Exception ignored) {
    }

  	// 第二步的实现方案和第一步其实一样,所以忽略
    ...

   	// 第三步,在我的版本源码中ObjectInputStream找不到newInstance方法,所以忽略
  	... 	
  }

sun.misc.Unsafe,可以无视对象的构造方法,创建新的对象 sun.misc.Unsafesh收集了很多底层的不安全的操作方法。尽管类和方法是开放的,但是要谨慎的使用它,因为只有信任的代码才可以使用它。 allocateInstance方法:创建一个实例,但是不运行它的构造方法,请手动初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
data class PigStoreResponse(
    val code: Int,
    var `data`: String,
    val msg: String
){
    init {
      print("init")
    }
}
var json = "{\"code\":1}"
var data = Gson().fromJson(json, PigStoreResponse::class.java)
if (data.data != null) {
    println("if")
} else {
    println("else")
}
// println结果:
// else

结论:

  • 在《if (data.data != null) 》处没有报错,代表即使声明为非空变量,在做null判断的时候也不会报错;
  • 没有执行《print(“init”)》表示,Gson对于(没有无参构造方法的类) 是不执行构造方法的

fastJson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
    "data": [
      {
        "refId": "EIJHOVJL732BNIFEF",
        "type": "cube",
        "version": "14",
      },
       {
        "refId": "EIJHOVJL732BNIFEF",
        "type": "cube",
        "version": "14",
      }
    ]
  }

如果使用 fastJson 解析上面的 json 字符串

1
2
3
4
5
6
7
8
9
obj.getJSONArray("data")// 可以正常获取数据,多次调用 obj.getJSONArray("data") 获取到的是同一个对象。
obj.getString("data");// 可以获取一个 Json 字符串
obj.getIntValue("data") // 会抛出异常 com.alibaba.fastjson.JSONException
obj.getJSONObject("data") // 会抛出异常 com.alibaba.fastjson.JSONException
obj.getInvalue("ddddd") // 如果使用一个不存在的 key 获取到的是 0
obj.getInteger("ddddd")// 获取到的是 null,如果key不存在,get 任何对象类型的数据获取到的都是 null

obj.getJSONArray("data").getJSONObject(0)// 能正常获取数据 
obj.getJSONArray("data").getJSONArray(0)// Method threw 'java.lang.ClassCastException' exception.  com.alibaba.fastjson.JSONObject cannot be cast to com.alibaba.fastjson.JSONArray

org.json.JSONObject

待补充

fastJson Gson 在使用时的区别

使用 fastJson 在 toJson 的时候,遍历的是对象以get开头的方法 和 public 属性的成员便来给你 使用 Gson 在 toJson 的时候,遍历的是对象的成员变量