泛型类型解析
如果顶层类型中存在泛型,就会出现不知道确切类型的状况,因为Class是无法携带泛型信息的,Java中不存在一个类型为List<String>.class,如果这样使用,Fastjson会将对象解析成JSONObject。 alibaba fastjson提供了一套TypeReference相关的方法来解决这个问题,从源代码来看定义不是很长:- public class TypeReference<T> {
- private final Type type;
- protected TypeReference(){
- Type superClass = getClass().getGenericSuperclass();
- type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
- }
- public Type getType() {
- return type;
- }
- public final static Type LIST_STRING = new TypeReference<List<String>>() {}.getType();
- }
getGenericSuperclass
public Type getGenericSuperclass()
如果超类是参数化类型,则返回的 Type 对象必须准确反映源代码中所使用的实际类型参数。如果以前未曾创建表示超类的参数化类型,则创建这个类型。有关参数化类型创建过程的语义,请参阅 ParameterizedType
声明。如果此 Class 表示 Object 类、接口、基本类型或 void,则返回 null。如果此对象表示一个数组类,则返回表示 Object 类的 Class 对象。
GenericSignatureFormatError
- 如果常规类签名不符合 Java Virtual Machine Specification, 3rd edition 规定的格式
TypeNotPresentException
- 如果常规超类引用不存在的类型声明
MalformedParameterizedTypeException
- 如果常规超类引用的参数化类型由于某种原因无法实例化
getActualTypeArguments
Type[] getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组。
注意,在某些情况下,返回的数组为空。如果此类型表示嵌套在参数化类型中的非参数化类型,则会发生这种情况。
返回:表示此类型的实际类型参数的 Type 对象的数组抛出:
TypeNotPresentException
- 如果任何实际类型参数引用不存在的类型声明MalformedParameterizedTypeException
- 如果任何实际类型参数引用参数化类型,该类型出于某种原因无法被实例化从以下版本开始:1.5
所以使用该类的方法只有一种,就是继承,因此其构造方法为protected,只能允许子类来调用,在构造该对象时,就需要在声明最后加上{}来表示继承关系。
- java.util.Map<java.lang.String, com.xxx.commons.json.test.JsonTest$InnerObj>
关于类型转换
如果是数组,由于某种对象的数组是存在对应的Class类型信息的,也就是说可以直接直接以Class的方式转换成功。 当时如果没有指定类型,就会转换成JSONObject,在其中以key/value的方式(类似Map)存储。 如果是数组,转成JSONArray,在其中包装JSONObject如果我们使用TypeReference,指定其为List<String>,而List中其实是对象,那么直接转换成String,此时字符串就为json字符串。 如果事先不知道该json串的类型信息(json事先也无法知道其类型信息,而Java的序列化,是带类型信息的,因此携带的内容也要比json串丰富地多,耗费网络带宽也大),或者在Map中写不出统一的泛型,那么就会发生隐性的类型转换过程。在codehaus jackson中会将无法识别的json对象直接转换成Map(key,value)格式,如果是fastjson,则转换成JSONObject(其实也类似于json)。如果需要将该对象仍然转换成json格式,不会有任何问题,但如果想要以原来的对象方式操作它,就会出现问题了(因为没有对象信息,除非手动将其转换,但每部分都需要手写代码,比较麻烦)。 Map中字段为null不被持久化的问题 如果Map中的某个属性为null,并不会被持久化,可以参考 https://segmentfault.com/q/1010000004216492 如果想让Map中的字段能够正常输出(这也是我们需要的),就需要在转换toJSONString时设置特殊的Feature来完成该功能:
- JSON.toJSONString(object, SerializerFeature.WriteMapNullValue)
关于Feature
参考:http://zyjustin9.iteye.com/blog/2020533, Fastjson中存在多种SerializerFeature,可以按照需要使用,例如- SerializerFeature.UseSingleQuotes,//支持单引号
- SerializerFeature.WriteDateUseDateFormat,//日期格式化
- SerializerFeature.WriteMapNullValue, // 输出空置字段
- SerializerFeature.WriteNullListAsEmpty, // list字段如果为null,输出为[],而不是null
- SerializerFeature.WriteNullNumberAsZero, // 数值字段如果为null,输出为0,而不是null
- SerializerFeature.WriteNullBooleanAsFalse, // Boolean字段如果为null,输出为false,而不是null
- SerializerFeature.WriteNullStringAsEmpty // 字符类型字段如果为null,输出为"",而不是null
- {"@type":"java.awt.Color","r":255,"g":0,"b":0,"alpha":255}
- String text = ...; // {"@type":"java.awt.Color","r":255,"g":0,"b":0,"alpha":255}
- Color color = (Color) JSON.parse(text);
- String text = ...; // [{/* header */}, {/* body */}]
- Type[] types = new Type[] {Header.class, Body.class};
- List<Object> list = JSON.parseArray(text, types);
- Header header = (Header) list.get(0);
- Body body = (Body) list.get(1);
- /**
- * @author wenshao[szujobs@hotmail.com]
- */
- public class JSONArray extends JSON implements List<Object>, Cloneable, RandomAccess, Serializable {
但在1.2.9版本并没有看到这个Feature,所以还是拭目以待吧。 <!--?xml version="1.0" encoding="UTF-8" standalone="no"?-->此外,我们在使用SpringMVC时,默认使用的json格式RequestMapper转换实现应该是jackson实现的,当然可以将其替换成fastjson的实现:
- <bean
- class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
- <!-- HandlerAdapter -->
- <bean
- class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
- <property name="messageConverters">
- <list>
- <bean
- class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
- <property name="features">
- <array value-type="com.alibaba.fastjson.serializer.SerializerFeature">
- <value>WriteDateUseDateFormat</value>
- <value>WriteMapNullValue</value>
- </array>
- </property>
- </bean>
- </list>
- </property>
- </bean>