APIJSON(八:AbstractObjectParser源码阅读(5))
2021SC@SDUSC
onChildParse
onChildPaerse函数主要用于解析子对象。
首先进行了isFirst和isMain的判定——
boolean isFirst = index <= 0;
boolean isMain = isFirst && type == TYPE_ITEM;
如果index索引是第一个的话,就说明是isFirst,在此基础上,如果type为TYPE_ITEM的话,就说明是isMain。
之后的话,对JSONObject的形式进行了判断——分别就Array与Object这两种形式做了不同对应的处理。
isArrayKey
if (apijson.JSONObject.isArrayKey(key)) {//APIJSON Array
if (isMain) {
throw new IllegalArgumentException(parentPath + "/" + key + ":{} 不合法!"
+ "数组 []:{} 中第一个 key:{} 必须是主表 TableKey:{} !不能为 arrayKey[]:{} !");
}
if (arrayConfig == null || arrayConfig.getPosition() == 0) {
arrayCount ++;
int maxArrayCount = parser.getMaxArrayCount();
if (arrayCount > maxArrayCount) {
throw new IllegalArgumentException(path + " 内截至 " + key + ":{} 时数组对象 key[]:{} 的数量达到 " + arrayCount + " 已超限,必须在 0-" + maxArrayCount + " 内 !");
}
}
首先注意到isArrayKey()这一函数——
public static boolean isArrayKey(String key) {
return key != null && key.endsWith(KEY_ARRAY);
}
它通过key不为空及key以KEY_ARRAY结尾来进行判断,判断是否为Array的key。
之后,如果前面的isMain判定成立,就会直接报错——数组 []:{} 中第一个 key:{} 必须是主表 TableKey:{} !不能为 arrayKey[]:{} !
其次,如果arrayConfig为空或者table在[]中的位置为第一位的话,就会令arrayCount+1位,如果超出maxArrayCount(的上限),就会报错。
之后会对对象数组进行获取,并进行isEmpty的判断。
child = parser.onArrayParse(value, path, key, isSubquery);
isEmpty = child == null || ((JSONArray) child).isEmpty();
isObjectKey
else { //APIJSON Object
boolean isTableKey = JSONRequest.isTableKey(Pair.parseEntry(key, true).getKey());
if (type == TYPE_ITEM && isTableKey == false) {
throw new IllegalArgumentException(parentPath + "/" + key + ":{} 不合法!"
+ "数组 []:{} 中每个 key:{} 都必须是表 TableKey:{} 或 数组 arrayKey[]:{} !");
}
if ( //避免使用 "test":{"Test":{}} 绕过限制,实现查询爆炸 isTableKey &&
(arrayConfig == null || arrayConfig.getPosition() == 0)) {
objectCount ++;
int maxObjectCount = parser.getMaxObjectCount();
if (objectCount > maxObjectCount) { //TODO 这里判断是批量新增/修改,然后上限为 maxUpdateCount
throw new IllegalArgumentException(path + " 内截至 " + key + ":{} 时对象"
+ " key:{} 的数量达到 " + objectCount + " 已超限,必须在 0-" + maxObjectCount + " 内 !");
}
}
如果key的类型为Object,首先会通过isTableKey函数判断是否为对应Table数组的 key。
之后,如果type不为TYPE_ITEM且,key也不是对应Table数组的,就会进行报错——数组 []:{} 中每个 key:{} 都必须是表 TableKey:{} 或 数组 arrayKey[]:{} !
之后如果key为对应Table数组的,就会进行跟上面一样的是否超出maxArrayCount(的上限)的判断。
之后会对单个对象进行获取,这里会根据isMain来确定是使用type或是使用null。
child = parser.onObjectParse(value, path, key, isMain ? arrayConfig.setType(SQLConfig.TYPE_ITEM_CHILD_0) : null, isSubquery);
isEmpty = child == null || ((JSONObject) child).isEmpty();
最后同样会进行isEmpty的判断。
if (isFirst && isEmpty) {
invalidate();
}
同时,如果第一个就位空,就会返回无效。
最后,整个函数会根据是否为空决定返回null或是返回child即该函数所获取的对象。
return isEmpty ? null : child;
onPUTArrayParse
此函数主要用来修改数组 PUT key:[]
首先如果既不是table,array也是空的,就会不做任何处理,直接返回
if (isTable == false || array.isEmpty()) {
Log.e(TAG, "onPUTArrayParse isTable == false || array == null || array.isEmpty() >> return;");
return;
}
接下来会对putType进行定义,这将会影响到之后的处理——
int putType = 0;
if (key.endsWith("+")) {//add
putType = 1;
} else if (key.endsWith("-")) {//remove
putType = 2;
}
而定义的主要根据就是以什么符号结尾,值默认为0,如果是以+结尾,就会将putType置为1,如果以-结尾,就会将putType置为2.
之后会使用getRealKey()方法,获取客户端实际需要的key。
String realKey = AbstractSQLConfig.getRealKey(method, key, false, false);
之后创建了一个新的JSONObject对象,并用put方法在这里面插入了KEY_ID和KEY_COLUMN对应的键值对。
JSONObject rq = new JSONObject();
rq.put(JSONRequest.KEY_ID, request.get(JSONRequest.KEY_ID));
rq.put(JSONRequest.KEY_COLUMN, realKey);
JSONObject rp = parseResponse(RequestMethod.GET, table, null, rq, null, false);
并将rp进行parseResponse处理,即返回执行对应的sql的结果
再之后就是对targetArray进行定义,其主要就是将rp的值赋进targetArray中(针对rp为空的情况,就会创建一个空的JSONArray
JSONArray targetArray = rp == null ? null : rp.getJSONArray(realKey);
if (targetArray == null) {
targetArray = new JSONArray();
}
Json对象中添加的是键值对,JSONArray中添加的是Json对象
之后就是针对targetArray和array做处理了
for (Object obj : array) {
if (obj == null) {
continue;
}
if (putType == 1) {
if (targetArray.contains(obj)) {
throw new ConflictException("PUT " + path + ", " + realKey + ":" + obj + " 已存在!");
}
targetArray.add(obj);
} else if (putType == 2) {
if (targetArray.contains(obj) == false) {
throw new NullPointerException("PUT " + path + ", " + realKey + ":" + obj + " 不存在!");
}
targetArray.remove(obj);
}
}
首先注意到for (Object obj : array)这个for循环
obj 是 Object 的一个实例对象,
整句话的意思就是,for循环array集合,这个集合,里面的对象类型是Object,取出array集合中的每个Object对象,实例化成obj小对象。然后就可以直接操作array中的这些Object类型的对象了。
jdk1.5新增迭代器for循环
(集合元素类型 局部变量 : 集合对象)
for (Object obj : collection)
将collection按顺序赋给obj,输出obj
首先,如果obj为空,就跳过。
在key是以+结尾(putType == 1)的情况下,会进行targetArray.contains的判断
contains是判断元素是否在动态数组中。
如果obj已经在targetArray中,就会报错。否则,就加入这个obj。
在key是以-结尾(putType == 2)的情况下,则刚好相反——
如果obj不在targetArray中,就会报错。否则,就移除这个obj。
程序的最后,在sqlRequest中插入(realKey, targetArray)键值对
sqlRequest.put(realKey, targetArray);
targetArray中,就会报错。否则,就加入这个obj。
在key是以-结尾(putType == 2)的情况下,则刚好相反——
如果obj不在targetArray中,就会报错。否则,就移除这个obj。
程序的最后,在sqlRequest中插入(realKey, targetArray)键值对
sqlRequest.put(realKey, targetArray);