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。
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非相关类型时报异常。
@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数量的空格占位。