当我调用JSONArray.put(Collection)这个方法想将集合直接转换成JSONArray对象时,发现,如果集合中的JavaBean如果没有添加 getter and setter,则转换后的JSONArray长度为集合长度,但无值,即:[{},{}]...,但是如果写了getter and setter方法,则能转换正常。 于是乎,跟进代码,首先是put:
/**
* Put a value in the JSONArray, where the value will be a JSONArray which
* is produced from a Collection.
*
* @param value
* A Collection value.
* @return this.
*/
public JSONArray put(Collection<?> value) {
this.put(new JSONArray(value));
return this;
}
发现这里调用了JSONArray的构造函数,继续跟进
/**
* Construct a JSONArray from a Collection.
*
* @param collection
* A Collection.
*/
public JSONArray(Collection<?> collection) {
this.myArrayList = new ArrayList<Object>();
if (collection != null) {
for (Object o: collection){
this.myArrayList.add(JSONObject.wrap(o));
}
}
}
到了这里,调用了JSONObject的wrap方法
/**
* Wrap an object, if necessary. If the object is null, return the NULL
* object. If it is an array or collection, wrap it in a JSONArray. If it is
* a map, wrap it in a JSONObject. If it is a standard property (Double,
* String, et al) then it is already wrapped. Otherwise, if it comes from
* one of the java packages, turn it into a string. And if it doesn't, try
* to wrap it in a JSONObject. If the wrapping fails, then null is returned.
*
* @param object
* The object to wrap
* @return The wrapped value
*/
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;
}
}
当然这个wrap方法只是啰嗦的写了一堆判断这个Object类型的代码,可以忽视,这里又调用到了JSONObject的构造函数
public JSONObject(Object bean) {
this();
this.populateMap(bean);
}
重点来了,就是这里调用的populateMap方法
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 (int i = 0; i < methods.length; i += 1) {
try {
Method method = methods[i];
if (Modifier.isPublic(method.getModifiers())) {
String name = method.getName();
String key = "";
if (name.startsWith("get")) {
if ("getClass".equals(name)
|| "getDeclaringClass".equals(name)) {
key = "";
} else {
key = name.substring(3);
}
} else if (name.startsWith("is")) {
key = name.substring(2);
}
if (key.length() > 0
&& Character.isUpperCase(key.charAt(0))
&& method.getParameterTypes().length == 0) {
if (key.length() == 1) {
key = key.toLowerCase();
} else if (!Character.isUpperCase(key.charAt(1))) {
key = key.substring(0, 1).toLowerCase()
+ key.substring(1);
}
Object result = method.invoke(bean, (Object[]) null);
if (result != null) {
this.map.put(key, wrap(result));
}
}
}
} catch (Exception ignore) {
}
}
}
看到这里,大家应该也明白了为什么不写getter and setter会拿不到值了,这里仅仅只是根据method[]去判断,如果有get方法,或者有isxxx方法,才会去获取到key值,然后判断key值的长度,如果大于0,说明找到了该字段,并获取到了其字段值,最后添加到集合中,所以在找不到这些方法的时候,也就拿不到值,也就不会调用this.map.put(key, value),最终返回也就是一个空的JSONArray了。 不知道是否是设计缺陷或者是其它考虑,暂时没有想过,既然发现了问题,那么自己就动手改一改,将这个"缺陷"修复,然后再使用!