在项目中遇到了一个JSON的坑。记录下。javascript
直接上代码:html
import java.util.ArrayList; import com.alibaba.fastjson.JSON; public class MyList<E> extends ArrayList<E> { private int size; private String specialName; public MyList(){ super(0); } public MyList(int size){ super(0); this.size = size; } public MyList(String specialName){ super(0); this.specialName = specialName; } public MyList(int size, String specialName){ super(0); this.size = size; this.specialName = specialName; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public String getSpecialName() { return specialName; } public void setSpecialName(String specialName) { this.specialName = specialName; } public static void main(String[] args){ MyList<Integer> list = new MyList<Integer>(); list.add(1); list.add(2); list.add(3); list.add(4); list.setSpecialName("just a test"); list.setSize(4); System.out.println(JSON.toJSON(list)); System.out.println(JSON.toJSONString(list)); } }
输出的结果为:java
[1,2,3,4] [1,2,3,4]
可是咱们指望的结果倒是相似于下面这样的结果:json
{size:4, specialName:"just a test", [1,2,3,4]}
那么是哪里出问题了呢?致使 MyList的 size 属性和 specialName 在JSON格式化时,被丢弃了呢?数组
下面在看一个例子:app
import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.alibaba.fastjson.JSON; public class MyList2<E> { private int size; private String specialName; private List<E> list; public MyList2(){ } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public String getSpecialName() { return specialName; } public void setSpecialName(String specialName) { this.specialName = specialName; } public List<E> getList() { return list; } public void setList(List<E> list) { this.list = list; } public static void main(String[] args){ MyList2<Integer> myList = new MyList2<Integer>(); ArrayList<Integer> list = new ArrayList<>(); list.add(1); list.add(2); list.add(3); list.add(4); myList.setSpecialName("just a test"); myList.setSize(4); myList.setList(list); System.out.println(JSON.toJSON(myList)); System.out.println(JSON.toJSONString(myList)); System.out.println("----------------"); Map<String, Object> map = new HashMap<>(); map.put("size", 4); map.put("specialName", "just a test"); map.put("list", list); map.put("myList", myList); System.out.println(JSON.toJSON(map)); } }
输出的结果为:this
{"list":[1,2,3,4],"size":4,"specialName":"just a test"} {"list":[1,2,3,4],"size":4,"specialName":"just a test"} ---------------- {"specialName":"just a test","size":4,"list":[1,2,3,4],"myList":{"list":[1,2,3,4],"size":4,"spe...
结果彻底正确。调试
到这里,咱们应该能够知道什么缘由了。code
上面第一段代码咱们指望的结果:htm
{size:4, specialName:"just a test", [1,2,3,4]}
可是想想,这个格式有什么问题吗?仔细想想。
FK,这个格式是彻底错误的!他是不合法的。试想一下,JSON格式说白了,它是 Javascript 的一个子集,合法的json对象它是 javascript 中的对象,可是:
{size:4, specialName:"just a test", [1,2,3,4]}
他是一个合法的javascript对象吗????
显然,它不是的。由于其中的 [1,2,3,4] ,咱们没法访问,它没有对应到一个属性。因此咱们没法访问它。因此他不是一个合法的javascript对象,显然也就更加不是一个合法的json对象了。因此第一个例子,输出的结果:[1,2,3,4] 实际上是能够接受的。
是咱们本身想要将一个不适合转化成JSON格式的Java对象强制转化成一个json格式,因此也就不免出现意料以外的状况了。那么 [1,2,3,4] 这个结果是如何来的呢。通过调试,其中的缘由是,由于MyList继承自ArrayList,因此在JSON格式化时,就是将其做为了一个List或者说数组来处理的,咱们看下相关源码:
public static final Object toJSON(Object javaObject) { return toJSON(javaObject, ParserConfig.getGlobalInstance()); } @SuppressWarnings("unchecked") public static final Object toJSON(Object javaObject, ParserConfig mapping) { if (javaObject == null) { return null; } if (javaObject instanceof JSON) { return (JSON) javaObject; } if (javaObject instanceof Map) { Map<Object, Object> map = (Map<Object, Object>) javaObject; JSONObject json = new JSONObject(map.size()); for (Map.Entry<Object, Object> entry : map.entrySet()) { Object key = entry.getKey(); String jsonKey = TypeUtils.castToString(key); Object jsonValue = toJSON(entry.getValue()); json.put(jsonKey, jsonValue); } return json; } if (javaObject instanceof Collection) { Collection<Object> collection = (Collection<Object>) javaObject; JSONArray array = new JSONArray(collection.size()); for (Object item : collection) { Object jsonValue = toJSON(item); array.add(jsonValue); } return array; }
咱们的MyList的对象,在 if (javaObject instanceof Collection) 处为true,因此被当作了JSONArray 来处理的,每次处理JSONArray 中的一项,因此显然就不会处理到 size属性和specialName属性了,因此这两个属性被抛弃了。这是 JSON.toJSON() 的处理过程。
下面看下 JSON.toJSONString(),其实也是同样,当成了数组或者说List来处理了:
上面的代码 else if (List.class.isAssignableFrom(clazz)) 处为 true,因此实际上是使用了 ListSerializer.instance 来处理了 MyList 的对象的,也就是当作了java.util.List 来处理的,因此天然就抛弃了 size属性和specialName属性。和上面的原理是同样的。
总结下:
1)MyList这样继承自List的对象,而且有扩展属性的,它在json格式中是不能十分恰当的表示的,它会被当成List来处理,从而抛弃其它非List的属性。
2)避免方法就是使用组合代替继承,或者使用Map,java.util.Map 天生就和json格式是最合适的,其实javascript中的对象,其实在某种程度上就是一个Map而已,属性名就是map中的key, 属性的值就是map的value。
3)JSON格式介绍参见:http://www.cnblogs.com/digdeep/p/4572662.html
转载自:http://www.bkjia.com/Javabc/1020836.html