说说org.json.JSONObject功能和源码(一)

      org json是一使用很简单易用的java JSON处理工具,最新版的jar只有64KB,比阿里的fastjson小很多。我介绍下源码和不常使用的功能。简单JSON对象格式如:

{"name":"shanks","sex":"male","msg":{"province":"beijing","code":"000000"}}

Maven:


    org.json
    json
    20180130

JSONObject数据结构是一个HashMap,即所有增删改查都是在操作一个HashMap对象。它有9个构造器。

默认构造器:

public JSONObject() {
     this.map = new HashMap();
}

构造器2:

protected JSONObject(int initialCapacity){
     this.map = new HashMap(initialCapacity);
}

创建一个初始容量为initialCapacity的HashMap,访问权限是protected。

构造器3:

public JSONObject(JSONObject jo, String[] names) {
        this(names.length);
        for (int i = 0; i < names.length; i += 1) {
            try {
                this.putOnce(names[i], jo.opt(names[i]));
            } catch (Exception ignore) {
            }
        }
    }

      这里putOnce(String key, Object value) 将一个非空的key和value存入当前对象,并且当前对象里没有要加入的key。将对象jo所有key中按names数组中的值挑选出来保存,就是说JSONObject不能有value为null的键值对。

构造器4:

public JSONObject(Map m) {
        if (m == null) {
            this.map = new HashMap();
        } else {
            this.map = new HashMap(m.size());
        	for (final Entry e : m.entrySet()) {
                final Object value = e.getValue();
                if (value != null) {
                    this.map.put(String.valueOf(e.getKey()), wrap(value));
                }
            }
        }
    }

       不添加Map对象m中value为null的key。类方法wrap(Object object)是将object区别处理,null返回嵌套类对象NULL,数组和Collection转化成JSONArray,Map转化成JSONObject,java包类的对象转化成字符串,当然基本类型先直接返回。如果上述类型都不符合,按JSONObject处理,异常返回null。

public static Object wrap(Object object) {
        try {
            if (object == null) {
                return NULL;
            }
            if (object instanceof JSONObject || object instanceof JSONArray
                    || NULL.equals(object) || object instanceof JSONString
                    || object instanceof Byte || object instanceof Character
                    || object instanceof Short || object instanceof Integer
                    || object instanceof Long || object instanceof Boolean
                    || object instanceof Float || object instanceof Double
                    || object instanceof String || object instanceof BigInteger
                    || object instanceof BigDecimal || object instanceof Enum) {
                return object;
            }
            if (object instanceof Collection) {
                Collection coll = (Collection) object;
                return new JSONArray(coll);
            }
            if (object.getClass().isArray()) {
                return new JSONArray(object);
            }
            if (object instanceof Map) {
                Map map = (Map) object;
                return new JSONObject(map);
            }
            Package objectPackage = object.getClass().getPackage();
            String objectPackageName = objectPackage != null ? objectPackage
                    .getName() : "";
            if (objectPackageName.startsWith("java.")
                    || objectPackageName.startsWith("javax.")
                    || object.getClass().getClassLoader() == null) {
                return object.toString();
            }
            return new JSONObject(object);
        } catch (Exception exception) {
            return null;
        }
    }

构造器5:

public JSONObject(Object bean) {
    this();
    this.populateMap(bean);
}

       反射机制将bean中getter和is打头方法生成JSONObject,当然getter和is是有条件的,先看void populateMap(Object bean)代码:

private void populateMap(Object bean) {
        Class klass = bean.getClass();
// If klass is a System class then set includeSuperClass to false.
        boolean includeSuperClass = klass.getClassLoader() != null;
        Method[] methods = includeSuperClass ? klass.getMethods() : klass
                .getDeclaredMethods();
        for (final Method method : methods) {
            final int modifiers = method.getModifiers();
            if (Modifier.isPublic(modifiers)
                    && !Modifier.isStatic(modifiers)
                    && method.getParameterTypes().length == 0
                    && !method.isBridge()
                    && method.getReturnType() != Void.TYPE ) {
                final String name = method.getName();
                String key;
                if (name.startsWith("get")) {
                    if ("getClass".equals(name) || "getDeclaringClass".equals(name)) {
                        continue;
                    }
                    key = name.substring(3);
                } else if (name.startsWith("is")) {
                    key = name.substring(2);
                } else {
                    continue;
                }
                if (key.length() > 0
                        && Character.isUpperCase(key.charAt(0))) {
                    if (key.length() == 1) {
                        key = key.toLowerCase(Locale.ROOT);
                    } else if (!Character.isUpperCase(key.charAt(1))) {
                        key = key.substring(0, 1).toLowerCase(Locale.ROOT)
                                + key.substring(1);
                    }
                    try {
                        final Object result = method.invoke(bean);
                        if (result != null) {
                            this.map.put(key, wrap(result));
                            // we don't use the result anywhere outside of wrap
                            // if it's a resource we should be sure to close it after calling toString
                            if(result instanceof Closeable) {
                                try {
                                    ((Closeable)result).close();
                                } catch (IOException ignore) {
                                }
                            }
                        }
                    } catch (IllegalAccessException ignore) {
                    } catch (IllegalArgumentException ignore) {
                    } catch (InvocationTargetException ignore) {
                    }
                }
            }
        }
    }

      代码中对getter和is方法做了限制,需要公共、非静态、非桥接、无参数和返回值为void,当然method.invoke(bean)执行后的结果不要null。

构造器6:
public JSONObject(Object object, String names[]) {
        this(names.length);
        Class c = object.getClass();
        for (int i = 0; i < names.length; i += 1) {
            String name = names[i];
            try {
                this.putOpt(name, c.getField(name).get(object));
            } catch (Exception ignore) {
            }
        }
    }

      将数组name[]中元素充当key,object相应名字的公共属性值作为value,都非null。c.getField(name).get(object)意思是获取指定对象object上属性为name的值。

构造器7:

public JSONObject(String source) throws JSONException {
     this(new JSONTokener(source));
}

      用JSONObject字符串生成对象,这里就不仔细说,以后章节再单独讲一下JSONTokener这个类。

构造器8:

public JSONObject(String baseName, Locale locale) throws JSONException {
        this();
        ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale,
                Thread.currentThread().getContextClassLoader());
        Enumeration keys = bundle.getKeys();
        while (keys.hasMoreElements()) {
            Object key = keys.nextElement();
            if (key != null) {
                String[] path = ((String) key).split("\\.");
                int last = path.length - 1;
                JSONObject target = this;
                for (int i = 0; i < last; i += 1) {
                    String segment = path[i];
                    JSONObject nextTarget = target.optJSONObject(segment);
                    if (nextTarget == null) {
                        nextTarget = new JSONObject();
                        target.put(segment, nextTarget);
                    }
                    target = nextTarget;
                }
                target.put(path[last], bundle.getString((String) key));
            }
        }
    }
      ResourceBundle读取资源文件中的信息,例如在CLASSPATH路径下的资源文件test_en_US.properties内容如下:
china.province = hubei
msg.post.code = 000000
测试代码:
public class JSONObjectTest {
    public static void main(String[] a){
        Locale locale = new Locale("en","US") ;
        JSONObject bundleJSON = new JSONObject("test", locale);
        System.out.println(bundleJSON.toString());
    }
}
      Locale是一个国际化相关的类,可以指定一个具体的国家编码,找到相应的资源文件。当资源文件只有一个时加载这一个,如果加载中文,命名test_zh_CN.properties。该构造器会将资源文件中的内容解析成JSON:
{"msg":{"post":{"code":"000000"}},"china":{"province":"hubei"}}
org JSONObject有两种方式获取,例如getString(String key):
public String getString(String key) throws JSONException {
        Object object = this.get(key);
        if (object instanceof String) {
            return (String) object;
        }
        throw new JSONException("JSONObject[" + quote(key) + "] not a string.");
    }
optString(...):
public String optString(String key) {
        return this.optString(key, "");
    }
public String optString(String key, String defaultValue) {
    Object object = this.opt(key);
    return NULL.equals(object) ? defaultValue : object.toString();
}
        可知用optString()获取value时,会得到一个默认值,不会出现value非相关类型时报异常。

toString方法:
@Override
public String toString() {
        try {
            return this.toString(0);
        } catch (Exception e) {
            return null;
        }
    }

public String toString(int indentFactor) throws JSONException {
        StringWriter w = new StringWriter();
        synchronized (w.getBuffer()) {
            return this.write(w, indentFactor, 0).toString();
        }
    }
toString(int indentFactor)会输出indentFactor数量的空格占位。

你可能感兴趣的:(java)