fastJson是很常用的序列化工具,用了這么久一直想底層看一下它的設計,探究一下它序列化和反序列化效率高的秘密。現在從最基礎的用法開始,一點點揭開fastJson神秘的面紗。(版本:1.2.50)
實際工程里,最常用的就是序列化和反序列化:
ResultDO resultDO = new ResultDO();
String jsonStr = JSON.toJSONString(resultDO);
ResultDO resultDO2 = JSON.parseObject(jsonStr, new TypeReference() {});
一.序列化
1.先從JSON.toJSONString開始看。跟進到底層,最后會調用一個基本方法:
public static String toJSONString(Object object, // 被序列化的對象
SerializeConfig config, // 序列化全局配置
SerializeFilter[] filters, //序列化的過濾器
String dateFormat, //日期格式
int defaultFeatures, // 默認序列化特性
SerializerFeature... features //自定義的序列化特性) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
return out.toString();
} finally {
out.close();
}
}
(1)一開始,會初始化一個SerializeWriter,然后用自定義的features覆蓋defaultFeatures配置。
(2)然后初始化一個JSONSerializer對象,序列化結果寫入SerializeWriter的buffer屬性中。序列化執行的時候,會根據config查找具體的序列化處理器去做處理。
(3)然后是對日期格式和過濾器的判斷。
SerializerFeature的用法在另一片文章里面有介紹:https://mp.csdn.net/postedit/84296853
SerializeFilter用法不再贅述,可以戳github:https://github.com/alibaba/fastjson/wiki/SerializeFilter
2.進入到write方法:
public final void write(Object object) {
if (object == null) {
out.writeNull();
return;
}
Class clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
try {
writer.write(this, object, null, null, 0);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
在這步有一個getObjectWriter的方法,根據序列化對象的class類型,得到對應的序列化器。這段代碼比較長,但可以總結為幾種類型:
(1)從指定的目錄下META-INF/services/,用當前線程的類加載器去取實現AutowiredObjectSerializer的序列化器
(2)與第一種區別的地方在於加載器不同,此時嘗試用加載JSON的classLoader
(3)當前這種是針對傳進來的clazz的類型,去尋找對應的序列化器。
這里都是常用的一些類型,比如Map,List,Collection,Date,enum,Iterator等等。還有JSON相關的一些,JSONAware,JSONSerializable,JSONStreamAware 。
特殊處理,(a)java自帶圖形包java.awt (b)jdk8中的日期包、Optional、concurrent(c)oracle相關的類(d)springfox相關的類(e)guava框架中類
(4) 代理類,包括cglib或者javassist動態代理,或是jdk自帶的動態代理。
(5)自主創建序列化器,createJavaBeanSerializer,這個之后要重點描述
private ObjectSerializer getObjectWriter(Class clazz, boolean create) {
//private final IdentityHashMap serializers; serializer是一個定義的緩存map,key是Type,這里存放Class類型。value是對象的序列化器
ObjectSerializer writer = serializers.get(clazz);
//下面是依次對不同的情況去取序列化器
//1.從指定的目錄下META-INF/services/,去取實現AutowiredObjectSerializer的序列化器
if (writer == null) {
try {
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
if (!(o instanceof AutowiredObjectSerializer)) {
continue;
}
AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
for (Type forType : autowired.getAutowiredFor()) {
//如果存在,都放到serializers緩存中
put(forType, autowired);
}
}
} catch (ClassCastException ex) {
// skip
}
//嘗試在緩存找序列化器
writer = serializers.get(clazz);
}
//2.與第一種區別的地方在於加載器不同,此時嘗試用加載JSON的classLoader。
if (writer == null) {
final ClassLoader classLoader = JSON.class.getClassLoader();
if (classLoader != Thread.currentThread().getContextClassLoader()) {
try {
for (Object o : ServiceLoader.load(AutowiredObjectSerializer.class, classLoader)) {
if (!(o instanceof AutowiredObjectSerializer)) {
continue;
}
AutowiredObjectSerializer autowired = (AutowiredObjectSerializer) o;
for (Type forType : autowired.getAutowiredFor()) {
put(forType, autowired);
}
}
} catch (ClassCastException ex) {
// skip
}
writer = serializers.get(clazz);
}
}
//3.當前這種是針對傳進來的clazz的類型,去尋找對應的序列化器。
//這里都是常用的一些類型,比如Map,List,Collection,Date,enum,Iterator等等。還有JSON相關的一些,JSONAware,JSONSerializable,JSONStreamAware 。
//特殊處理,(1)java自帶圖形包java.awt (2)jdk8中的日期包、Optional、concurrent(3)oracle相關的類(4)springfox相關的類(5)guava框架中類
if (writer == null) {
String className = clazz.getName();
Class superClass;
if (Map.class.isAssignableFrom(clazz)) {
put(clazz, writer = MapSerializer.instance);
} else if (List.class.isAssignableFrom(clazz)) {
put(clazz, writer = ListSerializer.instance);
} else if (Collection.class.isAssignableFrom(clazz)) {
put(clazz, writer = CollectionCodec.instance);
} else if (Date.class.isAssignableFrom(clazz)) {
put(clazz, writer = DateCodec.instance);
} else if (JSONAware.class.isAssignableFrom(clazz)) {
put(clazz, writer = JSONAwareSerializer.instance);
} else if (JSONSerializable.class.isAssignableFrom(clazz)) {
put(clazz, writer = JSONSerializableSerializer.instance);
} else if (JSONStreamAware.class.isAssignableFrom(clazz)) {
put(clazz, writer = MiscCodec.instance);
} else if (clazz.isEnum()) {
JSONType jsonType = TypeUtils.getAnnotation(clazz, JSONType.class);
if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {
put(clazz, writer = createJavaBeanSerializer(clazz));
} else {
put(clazz, writer = EnumSerializer.instance);
}
} else if ((superClass = clazz.getSuperclass()) != null && superClass.isEnum()) {
JSONType jsonType = TypeUtils.getAnnotation(superClass, JSONType.class);
if (jsonType != null && jsonType.serializeEnumAsJavaBean()) {
put(clazz, writer = createJavaBeanSerializer(clazz));
} else {
put(clazz, writer = EnumSerializer.instance);
}
} else if (clazz.isArray()) {
Class componentType = clazz.getComponentType();
ObjectSerializer compObjectSerializer = getObjectWriter(componentType);
put(clazz, writer = new ArraySerializer(componentType, compObjectSerializer));
} else if (Throwable.class.isAssignableFrom(clazz)) {
SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy);
beanInfo.features |= SerializerFeature.WriteClassName.mask;
put(clazz, writer = new JavaBeanSerializer(beanInfo));
} else if (TimeZone.class.isAssignableFrom(clazz) || Map.Entry.class.isAssignableFrom(clazz)) {
put(clazz, writer = MiscCodec.instance);
} else if (Appendable.class.isAssignableFrom(clazz)) {
put(clazz, writer = AppendableSerializer.instance);
} else if (Charset.class.isAssignableFrom(clazz)) {
put(clazz, writer = ToStringSerializer.instance);
} else if (Enumeration.class.isAssignableFrom(clazz)) {
put(clazz, writer = EnumerationSerializer.instance);
} else if (Calendar.class.isAssignableFrom(clazz) //
|| XMLGregorianCalendar.class.isAssignableFrom(clazz)) {
put(clazz, writer = CalendarCodec.instance);
} else if (Clob.class.isAssignableFrom(clazz)) {
put(clazz, writer = ClobSeriliazer.instance);
} else if (TypeUtils.isPath(clazz)) {
put(clazz, writer = ToStringSerializer.instance);
} else if (Iterator.class.isAssignableFrom(clazz)) {
put(clazz, writer = MiscCodec.instance);
} else if (org.w3c.dom.Node.class.isAssignableFrom(clazz)) {
put(clazz, writer = MiscCodec.instance);
} else {
if (className.startsWith("java.awt.") //
&& AwtCodec.support(clazz) //
) {
// awt
if (!awtError) {
try {
String[] names = new String[]{
"java.awt.Color",
"java.awt.Font",
"java.awt.Point",
"java.awt.Rectangle"
};
for (String name : names) {
if (name.equals(className)) {
put(Class.forName(name), writer = AwtCodec.instance);
return writer;
}
}
} catch (Throwable e) {
awtError = true;
// skip
}
}
}
// jdk8
if ((!jdk8Error) //
&& (className.startsWith("java.time.") //
|| className.startsWith("java.util.Optional") //
|| className.equals("java.util.concurrent.atomic.LongAdder")
|| className.equals("java.util.concurrent.atomic.DoubleAdder")
)) {
try {
{
String[] names = new String[]{
"java.time.LocalDateTime",
"java.time.LocalDate",
"java.time.LocalTime",
"java.time.ZonedDateTime",
"java.time.OffsetDateTime",
"java.time.OffsetTime",
"java.time.ZoneOffset",
"java.time.ZoneRegion",
"java.time.Period",
"java.time.Duration",
"java.time.Instant"
};
for (String name : names) {
if (name.equals(className)) {
put(Class.forName(name), writer = Jdk8DateCodec.instance);
return writer;
}
}
}
{
String[] names = new String[]{
"java.util.Optional",
"java.util.OptionalDouble",
"java.util.OptionalInt",
"java.util.OptionalLong"
};
for (String name : names) {
if (name.equals(className)) {
put(Class.forName(name), writer = OptionalCodec.instance);
return writer;
}
}
}
{
String[] names = new String[]{
"java.util.concurrent.atomic.LongAdder",
"java.util.concurrent.atomic.DoubleAdder"
};
for (String name : names) {
if (name.equals(className)) {
put(Class.forName(name), writer = AdderSerializer.instance);
return writer;
}
}
}
} catch (Throwable e) {
// skip
jdk8Error = true;
}
}
if ((!oracleJdbcError) //
&& className.startsWith("oracle.sql.")) {
try {
String[] names = new String[] {
"oracle.sql.DATE",
"oracle.sql.TIMESTAMP"
};
for (String name : names) {
if (name.equals(className)) {
put(Class.forName(name), writer = DateCodec.instance);
return writer;
}
}
} catch (Throwable e) {
// skip
oracleJdbcError = true;
}
}
if ((!springfoxError) //
&& className.equals("springfox.documentation.spring.web.json.Json")) {
try {
put(Class.forName("springfox.documentation.spring.web.json.Json"), //
writer = SwaggerJsonSerializer.instance);
return writer;
} catch (ClassNotFoundException e) {
// skip
springfoxError = true;
}
}
if ((!guavaError) //
&& className.startsWith("com.google.common.collect.")) {
try {
String[] names = new String[] {
"com.google.common.collect.HashMultimap",
"com.google.common.collect.LinkedListMultimap",
"com.google.common.collect.ArrayListMultimap",
"com.google.common.collect.TreeMultimap"
};
for (String name : names) {
if (name.equals(className)) {
put(Class.forName(name), writer = GuavaCodec.instance);
return writer;
}
}
} catch (ClassNotFoundException e) {
// skip
guavaError = true;
}
}
if ((!jsonnullError) && className.equals("net.sf.json.JSONNull")) {
try {
put(Class.forName("net.sf.json.JSONNull"), writer = MiscCodec.instance);
return writer;
} catch (ClassNotFoundException e) {
// skip
jsonnullError = true;
}
}
//如果class實現唯一接口,並且接口包含注解,使用AnnotationSerializer序列化
Class[] interfaces = clazz.getInterfaces();
if (interfaces.length == 1 && interfaces[0].isAnnotation()) {
put(clazz, AnnotationSerializer.instance);
return AnnotationSerializer.instance;
}
//如果使用了cglib或者javassist動態代理
if (TypeUtils.isProxy(clazz)) {
//得到父類並獲取父類的序列化器
Class superClazz = clazz.getSuperclass();
ObjectSerializer superWriter = getObjectWriter(superClazz);
put(clazz, superWriter);
return superWriter;
}
//如果是jdk自帶的動態代理
if (Proxy.isProxyClass(clazz)) {
Class handlerClass = null;
//如果繼承兩個接口,取第二個接口做為handlerClass
if (interfaces.length == 2) {
handlerClass = interfaces[1];
} else {
for (Class proxiedInterface : interfaces) {
//spring切面相關的接口,跳過 if(proxiedInterface.getName().startsWith("org.springframework.aop.")) {
continue;
}
//如果除了aop的有多個接口,則跳出,並置handlerClass為null
if (handlerClass != null) {
handlerClass = null; // multi-matched
break;
}
handlerClass = proxiedInterface;
}
}
//handlerClass不為null,作為父類尋找序列化器,作為當前類的序列化器
if (handlerClass != null) {
ObjectSerializer superWriter = getObjectWriter(handlerClass);
put(clazz, superWriter);
return superWriter;
}
}
//如果開啟,使用JavaBeanSerializer 序列化
if (create) {
writer = createJavaBeanSerializer(clazz);
put(clazz, writer);
}
}
if (writer == null) {
writer = serializers.get(clazz);
}
}
return writer;
}
當使用toJSONString()方法時,如果不添加參數,默認create時true。大部分時候,我們要序列化的對象都是自定義的對象,所以進入createJavaBeanSerializer方法中一探究竟:
public final ObjectSerializer createJavaBeanSerializer(Class clazz) {
SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);
if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
return MiscCodec.instance;
}
return createJavaBeanSerializer(beanInfo);
}
TypeUtils.buildBeanInfo會創建一個SerializeBeanInfo對象,看一下它的幾個參數:
public static SerializeBeanInfo buildBeanInfo(Class beanType //
, Map aliasMap //
, PropertyNamingStrategy propertyNamingStrategy //
, boolean fieldBased //
){
...
}
(1)Class beanType :class對象類型
(2)Map aliasMap:序列化對象字段的map,配置的屬性真正的名稱。默認為null。
(3)PropertyNamingStrategy propertyNamingStrategy:命名方式,“駝峰式”等
(4)boolean fieldBased:判斷走哪一種收集fieldInfo的方法
理解完參數,再看下build的邏輯。代碼比較長,我們拆開看:
(1)jsonType:
我們結合例子一起看一下,JSONType和JSONField都可以定制序列化,可以設置包含,忽略,也可以設置格式。
//@JSONType(ignores ={"id", "sex"})
//@JSONType(includes={"name","sex"})
public class User {
@JSONField(name = "ID", ordinal = 3, serializeUsing = UserIDValueSerializer.class)
private Long id;
@JSONField(serialize = false)
private String name;
@JSONField(serialize = true, ordinal = 2)
private String sex;
@JSONField(deserialize = false)
private String address;
@JSONField(deserialize = true)
private String phone;
// 配置date序列化和反序列使用yyyyMMdd日期格式
@JSONField(format = "yyyyMMdd", ordinal = 1)
private Date date;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
//get and set ...
}
//1.尋找當前class對象中,是否有JSONType注解
//先查詢當前類,如果沒有,再查詢元素上存在的所有注解,包括從父類繼承的。
JSONType jsonType = TypeUtils.getAnnotation(beanType,JSONType.class);
String[] orders = null;
final int features;
String typeName = null, typeKey = null;
if(jsonType != null){
//獲取序列化的順序
orders = jsonType.orders();
typeName = jsonType.typeName();
if(typeName.length() == 0){
typeName = null;
}
//獲取命名類型,分為四種,以“personName”為例
//(1)CamelCase(personName) (2)PascalCase(PersonName)(3)SnakeCase(person_name)(4)KebabCase(person-name)
PropertyNamingStrategy jsonTypeNaming = jsonType.naming();
//如果不是默認的駝峰式,就說明用戶設置了name屬性,覆蓋傳進來的propertyNamingStrategy參數
if (jsonTypeNaming != PropertyNamingStrategy.CamelCase) {
propertyNamingStrategy = jsonTypeNaming;
}
// 形成新的features值。這里的位運算存儲很有意思,是一種很高效的設計。
features = SerializerFeature.of(jsonType.serialzeFeatures());
//循環向上尋找父類,如果找到有父類設置了typeKey,賦給變量存下來
for(Class supperClass = beanType.getSuperclass()
; supperClass != null && supperClass != Object.class
; supperClass = supperClass.getSuperclass()){
JSONType superJsonType = TypeUtils.getAnnotation(supperClass,JSONType.class);
if(superJsonType == null){
break;
}
typeKey = superJsonType.typeKey();
if(typeKey.length() != 0){
break;
}
}
//遍歷尋找當前類實現的接口,如果找到有父類設置了typeKey,賦給變量存下來
for(Class interfaceClass : beanType.getInterfaces()){
JSONType superJsonType = TypeUtils.getAnnotation(interfaceClass,JSONType.class);
if(superJsonType != null){
typeKey = superJsonType.typeKey();
if(typeKey.length() != 0){
break;
}
}
}
if(typeKey != null && typeKey.length() == 0){
typeKey = null;
}
} else{
features = 0;
}
聊一下SerializerFeature這個枚舉類:
SerializerFeature(){
mask = (1 << ordinal());
}
這個枚舉類是把所有feature按照順序,位偏移計算后,得到一個mask,作為當前feature的標記值。ordinal()的取值是0~Integer.MAX_VALUE。所以第一個枚舉類的值是 1,第二個是"10",第三個是"100",依次類推,可以存31個枚舉值。
所以每一位代表一個特征值,1是有,0是無。一個int數就可以表示當前設置了哪些特征值。
這種設計思路對項目開發是很有幫助的,畢竟位運算是最高效的運算。
Q:算上@Deprecated的,已經有30個特征值了,萬一以后多加了特征值該怎么存儲呢,直接把mask改為long型么?
接着看具體的解析:
這里分為兩種方式:(1)computeGettersWithFieldBase (2)computeGetters
// fieldName,field ,先生成fieldName的快照,減少之后的findField的輪詢
Map fieldCacheMap = new HashMap();
ParserConfig.parserAllFieldToCache(beanType, fieldCacheMap);
//根據fieldBased判斷走哪一個getter方法,默認是false。
List fieldInfoList = fieldBased
? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //
: computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);
FieldInfo[] fields = new FieldInfo[fieldInfoList.size()];
fieldInfoList.toArray(fields);
FieldInfo[] sortedFields;
List sortedFieldList;
if(orders != null && orders.length != 0){
sortedFieldList = fieldBased
? computeGettersWithFieldBase(beanType, aliasMap, true, propertyNamingStrategy) //
: computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, true, propertyNamingStrategy);
} else{
sortedFieldList = new ArrayList(fieldInfoList);
Collections.sort(sortedFieldList);
}
sortedFields = new FieldInfo[sortedFieldList.size()];
sortedFieldList.toArray(sortedFields);
if(Arrays.equals(sortedFields, fields)){
sortedFields = fields;
}
return new SerializeBeanInfo(beanType, jsonType, typeName, typeKey, features, fields, sortedFields);
先看一下computeGettersWithFieldBase方法:
public static List computeGettersWithFieldBase(
Class clazz, //
Map aliasMap, //
boolean sorted, //
PropertyNamingStrategy propertyNamingStrategy){
Map fieldInfoMap = new LinkedHashMap();
for(Class currentClass = clazz; currentClass != null; currentClass = currentClass.getSuperclass()){
Field[] fields = currentClass.getDeclaredFields();
computeFields(currentClass, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
}
return getFieldInfos(clazz, sorted, fieldInfoMap);
}
配合上面的例子,來看computeFields方法是如何一步步解析的:
private static void computeFields(
Class clazz, //
Map aliasMap, //
PropertyNamingStrategy propertyNamingStrategy, //
Map fieldInfoMap, //
Field[] fields){
for(Field field : fields){
//獲取屬性的修飾符。如果是靜態變量,則跳過,不放在fieldInfoMap中
if(Modifier.isStatic(field.getModifiers())){
continue;
}
//讀取JSONField注解,解析序列化的定制化配置
JSONField fieldAnnotation = field.getAnnotation(JSONField.class);
//不小心發現一個拼寫錯誤,“serialzeFeatures”。FieldInfo類里面的屬性也是這個。強迫症患者。
int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
String propertyName = field.getName();
String label = null;
if(fieldAnnotation != null){
//依次解析注解的serialize、ordinal、serialzeFeatures、parserFeatures、propertyName、label屬性,這個例子里可以看到
if(!fieldAnnotation.serialize()){
continue;
}
ordinal = fieldAnnotation.ordinal();
serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
if(fieldAnnotation.name().length() != 0){
propertyName = fieldAnnotation.name();
}
if(fieldAnnotation.label().length() != 0){
label = fieldAnnotation.label();
}
}
//如果傳入的aliasMap不為null,就用別名。如果別名為null,就直接跳過
//Q:aliasMap會存放所有屬性的別名么?如果不是,等於null就跳過,那這個屬性就被拋棄了,不會放到fieldInfoMap中。
if(aliasMap != null){
propertyName = aliasMap.get(propertyName);
if(propertyName == null){
continue;
}
}
//屬性的命名策略,修改格式
if(propertyNamingStrategy != null){
propertyName = propertyNamingStrategy.translate(propertyName);
}
//生成FieldInfo,並放到map中
if(!fieldInfoMap.containsKey(propertyName)){
FieldInfo fieldInfo = new FieldInfo(propertyName, null, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
null, fieldAnnotation, label);
fieldInfoMap.put(propertyName, fieldInfo);
}
}
}
再看一下 computeGetters方法:
public static List computeGetters(Class clazz, //
JSONType jsonType, //
Map aliasMap, //
Map fieldCacheMap, //
boolean sorted, //
PropertyNamingStrategy propertyNamingStrategy //
){
Map fieldInfoMap = new LinkedHashMap();
boolean kotlin = TypeUtils.isKotlin(clazz);
// for kotlin
Constructor[] constructors = null;
Annotation[][] paramAnnotationArrays = null;
String[] paramNames = null;
short[] paramNameMapping = null;
Method[] methods = clazz.getMethods();
for(Method method : methods){
String methodName = method.getName();
int ordinal = 0, serialzeFeatures = 0, parserFeatures = 0;
String label = null;
//對特殊情況的判斷(序列化目標是尋找get方法)
//(1)靜態方法(2)返回類型是void(3)參數類型數組長度不是0.也就是存在參數(4)返回類類型是類加載器(5)groovy的MetaClass(6)異常處理getSuppressed(7)Kotlin類型
if(Modifier.isStatic(method.getModifiers())){
continue;
}
。。。
/**
* 如果在屬性或者方法上存在JSONField注解,並且定制了name屬性,不以類上的propertyNamingStrategy設置為准,以此字段的JSONField的name定制為准。
*/
Boolean fieldAnnotationAndNameExists = false;
//判斷是否有JSONField注解
JSONField annotation = method.getAnnotation(JSONField.class);
if(annotation == null){
annotation = getSuperMethodAnnotation(clazz, method);
}
//kotlin相關,不常用到
if(annotation == null && kotlin){
。。。
}
//如果有注解,讀取注解中定義的name,feature等參數
if(annotation != null){
if(!annotation.serialize()){
continue;
}
ordinal = annotation.ordinal();
serialzeFeatures = SerializerFeature.of(annotation.serialzeFeatures());
parserFeatures = Feature.of(annotation.parseFeatures());
if(annotation.name().length() != 0){
String propertyName = annotation.name();
if(aliasMap != null){
propertyName = aliasMap.get(propertyName);
if(propertyName == null){
continue;
}
}
FieldInfo fieldInfo = new FieldInfo(propertyName, method, null, clazz, null, ordinal,
serialzeFeatures, parserFeatures, annotation, null, label);
fieldInfoMap.put(propertyName, fieldInfo);
continue;
}
if(annotation.label().length() != 0){
label = annotation.label();
}
}
//常用方法,判斷方法是否以“get”開頭
if(methodName.startsWith("get")){
//排除特殊情況(1)長度<4(2)getClass (3)枚舉類的getDeclaringClass
if(methodName.length() < 4){
continue;
}
if(methodName.equals("getClass")){
continue;
}
if(methodName.equals("getDeclaringClass") && clazz.isEnum()){
continue;
}
char c3 = methodName.charAt(3);
String propertyName;
//開始解析get方法,判斷get之后的第一個字符c3
//1、如果c3是大寫,判斷compatibleWithJavaBean屬性(默認為false),
//如果為true,截取get后的字符串,如果前兩位都是大寫,則直接返回;其他情況,把首字母變小寫返回。
//如果是false,直接把get后字符串的第一位變小寫返回。
//2.如果是'_','f'等特殊情況,按照各自規則截取。
if(Character.isUpperCase(c3) //
|| c3 > 512 // for unicode method name
){
if(compatibleWithJavaBean){
propertyName = decapitalize(methodName.substring(3));
} else{
propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}
//這里還有一個替換過程。還記得上面buildBeanInfo中生成的fieldCacheMap么,這里面存的是類得到的所有field。所以如果compatibleWithFieldName為true,代表按照field屬性的大小寫來,如果methodName的get方法之后的字符串在屬性map里面,就用map中存好的屬性。
propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 3);
} else if(c3 == '_'){
propertyName = methodName.substring(4);
} else if(c3 == 'f'){
propertyName = methodName.substring(3);
} else if(methodName.length() >= 5 && Character.isUpperCase(methodName.charAt(4))){
propertyName = decapitalize(methodName.substring(3));
} else{
continue;
}
//判斷JSONType注解的includes 和 ignores 屬性,如果是忽略的,跳過這個方法的屬性檢測。提一下,這里的比較是區分大小寫的equals,所以設置includes 和 ignores,最好看看它上述的解析規則,否則屬性設置未必生效。
boolean ignore = isJSONTypeIgnore(clazz, propertyName);
if(ignore){
continue;
}
//假如bean的field很多的情況一下,輪詢時將大大降低效率
//假設現在得到的propertyName是“personName”,getFieldFromCache會從不同key嘗試從fieldCacheMap獲取field。(1)"_personName"(2)"m_personName"(3)"PersonName"(4) propertyName長度大於2且首字母小寫,第二個字母大寫的時候,忽略大小寫從map中嘗試獲取。(不是很懂這個特殊邏輯)
Field field = ParserConfig.getFieldFromCache(propertyName, fieldCacheMap);
//如果還沒獲取到,且propertyName第二個字符是大寫,再得到javaBeanCompatiblePropertyName,嘗試從map中獲取。
if(field == null && propertyName.length() > 1){
char ch = propertyName.charAt(1);
if(ch >= 'A' && ch <= 'Z'){
String javaBeanCompatiblePropertyName = decapitalize(methodName.substring(3));
field = ParserConfig.getFieldFromCache(javaBeanCompatiblePropertyName, fieldCacheMap);
}
}
JSONField fieldAnnotation = null;
//檢測這個field是否有設置屬性
if(field != null){
fieldAnnotation = field.getAnnotation(JSONField.class);
if(fieldAnnotation != null){
if(!fieldAnnotation.serialize()){
continue;
}
ordinal = fieldAnnotation.ordinal();
serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
if(fieldAnnotation.name().length() != 0){
fieldAnnotationAndNameExists = true;
propertyName = fieldAnnotation.name();
if(aliasMap != null){
propertyName = aliasMap.get(propertyName);
if(propertyName == null){
continue;
}
}
}
if(fieldAnnotation.label().length() != 0){
label = fieldAnnotation.label();
}
}
}
//默認情況下,aliasMap為null
if(aliasMap != null){
propertyName = aliasMap.get(propertyName);
if(propertyName == null){
continue;
}
}
//propertyNamingStrategy不為null,修改格式
if(propertyNamingStrategy != null && !fieldAnnotationAndNameExists){
propertyName = propertyNamingStrategy.translate(propertyName);
}
FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
annotation, fieldAnnotation, label);
fieldInfoMap.put(propertyName, fieldInfo);
}
//如果是is開頭的,是類似的邏輯。不再贅述
if(methodName.startsWith("is")){
。。。
}
}
Field[] fields = clazz.getFields();
//最后再調用computeFields方法
computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
return getFieldInfos(clazz, sorted, fieldInfoMap);
}
小結一下computeGetters方法的邏輯:
(1)對特殊情況的判斷(序列化目標是尋找get方法)
(a)靜態方法
(b)返回類型是void
(c)參數類型數組長度不是0.也就是存在參數
(d)返回類類型是類加載器
(e)groovy的MetaClass
(f)異常處理getSuppressed
(g)Kotlin類型
(2) check當前的method是否有JSONField注解,並判斷是否是kotlin相關的類。 (JSONField可以設置在屬性上,也可以設置在方法上。)
(3)“get”開頭的解析。
(a)排除特殊情況:長度<4;getClass ;枚舉類的getDeclaringClass
(b) 開始解析get方法,判斷get之后的第一個字符c3。
如果c3是大寫,判斷compatibleWithJavaBean屬性(默認為false),如果為true,截取get后的字符串,如果前兩位都 是大寫,則直接返回;其他情況,把首字母變小寫返回。 如果是false,直接把get后字符串的第一位變小寫返回。如果是'_','f'等特殊情況,按照各自規則截取。
這里還有一個替換過程。傳進來的buildBeanInfo中生成的fieldCacheMap,這里面存的是類得到的所有field。所以如果compatibleWithFieldName為true,代表按照field屬性的大小寫來,如果methodName的get方法之后的字符串在屬性map里面,就用map中存好的屬性。
fastJson在多處用了這種map,優化了查詢的效率。
(4)對得到field中的JSONField注解做解析。
到這里,SerializeBeanInfo的步驟就基本完成了,接下來就是正式的去生成序列化器的方法createJavaBeanSerializer:
在之前先提一下,fastjson內嵌了ASM框架來動態生成類,ASMClassLoader繼承了java的類裝載器ClassLoader。
public ObjectSerializer createJavaBeanSerializer(SerializeBeanInfo beanInfo) {
JSONType jsonType = beanInfo.jsonType;
boolean asm = this.asm && !fieldBased;
//jsonType注解不為null
if (jsonType != null) {
//jsonType中設置的序列化器屬性,默認是Void.class
Class serializerClass = jsonType.serializer();
if (serializerClass != Void.class) {
try {
//如果是自己寫的序列化器,繼承了ObjectSerializer接口,直接返回用戶設定的序列化器。
Object seralizer = serializerClass.newInstance();
if (seralizer instanceof ObjectSerializer) {
return (ObjectSerializer) seralizer;
}
} catch (Throwable e) {
// skip
}
}
//jsonType設定了asm可用屬性。
if (jsonType.asm() == false) {
asm = false;
}
if (asm) {
//check:如果設置了下面的一些屬性,即使asm可用,也設置為不可用。
for (SerializerFeature feature : jsonType.serialzeFeatures()) {
if (SerializerFeature.WriteNonStringValueAsString == feature //
|| SerializerFeature.WriteEnumUsingToString == feature //
|| SerializerFeature.NotWriteDefaultValue == feature
|| SerializerFeature.BrowserCompatible == feature) {
asm = false;
break;
}
}
}
if (asm) {
//check:如果設置了過濾器,asm也禁用
final Class[] filterClasses = jsonType.serialzeFilters();
if (filterClasses.length != 0) {
asm = false;
}
}
}
Class clazz = beanInfo.beanType;
//如果bean是public的,直接用JavaBeanSerializer返回。
if (!Modifier.isPublic(beanInfo.beanType.getModifiers())) {
return new JavaBeanSerializer(beanInfo);
}無錫人流多少錢 http://www.bhnfkyy.com/
//(1)如果是類加載器在ASMClassLoader的外部(2)或者clazz就是 Serializable.class(3)clazz就是Object.class
if (asm && asmFactory.classLoader.isExternalClass(clazz)
|| clazz == Serializable.class || clazz == Object.class) {
asm = false;
}
//不符合asm的命名規則
if (asm && !ASMUtils.checkName(clazz.getSimpleName())) {
asm = false;
}
//接口
if (asm && beanInfo.beanType.isInterface()) {
asm = false;
}
if (asm) {
//對每一個屬性做check
for(FieldInfo fieldInfo : beanInfo.fields){
Field field = fieldInfo.field;
if (field != null && !field.getType().equals(fieldInfo.fieldClass)) {
asm = false;
break;
}
Method method = fieldInfo.method;
if (method != null && !method.getReturnType().equals(fieldInfo.fieldClass)) {
asm = false;
break;
}
JSONField annotation = fieldInfo.getAnnotation();
if (annotation == null) {
continue;
}
String format = annotation.format();
if (format.length() != 0) {
if (fieldInfo.fieldClass == String.class && "trim".equals(format)) {
} else {
asm = false;
break;
}
}
if ((!ASMUtils.checkName(annotation.name())) //
|| annotation.jsonDirect()
|| annotation.serializeUsing() != Void.class
|| annotation.unwrapped()
) {
asm = false;
break;
}
for (SerializerFeature feature : annotation.serialzeFeatures()) {
if (SerializerFeature.WriteNonStringValueAsString == feature //
|| SerializerFeature.WriteEnumUsingToString == feature //
|| SerializerFeature.NotWriteDefaultValue == feature
|| SerializerFeature.BrowserCompatible == feature
|| SerializerFeature.WriteClassName == feature) {
asm = false;
break;
}
}
if (TypeUtils.isAnnotationPresentOneToMany(method) || TypeUtils.isAnnotationPresentManyToMany(method)) {
asm = false;
break;
}
}
}
if (asm) {
try {
ObjectSerializer asmSerializer = createASMSerializer(beanInfo);
if (asmSerializer != null) {
return asmSerializer;
}
} catch (ClassNotFoundException ex) {
// skip
} catch (ClassFormatError e) {
// skip
} catch (ClassCastException e) {
// skip
} catch (OutOfMemoryError e) {
if (e.getMessage().indexOf("Metaspace") != -1) {
throw e;
}
// skip
} catch (Throwable e) {
throw new JSONException("create asm serializer error, verson " + JSON.VERSION + ", class " + clazz, e);
}
}
return new JavaBeanSerializer(beanInfo);
}
兩種得到序列化器的方法:(1)JavaBeanSerializer(2)createASMSerializer
使用asm的條件:
(1)JSONType注解設置了asm的屬性為不可用
(2)SerializerFeature設置某些序列化屬性,WriteNonStringValueAsString、WriteEnumUsingToString、NotWriteDefaultValue、BrowserCompatible。
(3)如果設置了過濾器,asm也禁用 。
(4)該clazz為非public類
(5) 該clazz的類加載器在ASMClassLoader的外部、clazz是Serializable.class或者Object.class
(6)不符合asm的命名規則、bean是接口類型
(7)對每一個field屬性的check,如果不滿足條件也禁用asm。