1. 程式人生 > >fastjson原始碼解析(2)-工具類TypeUtils

fastjson原始碼解析(2)-工具類TypeUtils

1.概述

   前面一篇文章介紹了IOutils,主要介紹了fastjson部分優化點和base64編解碼。這篇文章也是介紹fastjson的工具類,主要包含型別轉換。在fastjson核心程式碼中會經常使用這些方法,所以先提前解析這些方法。(原始碼解析中有部分後面的內容,暫時略過)

2. 原始碼解析

1.靜態變數
    /**
     * initialCapacity: map的初始大小
     * loadFactor: 載入因子
     * concurrencyLevel: 最大併發數
     */
	private static ConcurrentMap<String,Class<?>> mappings = new ConcurrentHashMap<String,Class<?>>(16, 0.75f, 1);

	static{
	   // 將常見的類新增到快取中,在原始碼中可以發現有大量的類新增到map中,建議將mappings的初始大小調高
        addBaseClassMappings();
    }
	

2.主要方法(如果功能差不多以具有代表性的一個或者幾個解析)
    /**
	 * Object轉換為Short型別
	 * 
	 */
    public static Short castToShort(Object value){
        if(value == null){
            return null;
        }
		// 數字型別
        if(value instanceof Number){
            return ((Number) value).shortValue();
        }
		// "null"或者"NULL"轉換為null
        if(value instanceof String){
            String strVal = (String) value;
            if(strVal.length() == 0 //
                    || "null".equals(strVal) //
                    || "NULL".equals(strVal)){
                return null;
            }
            return Short.parseShort(strVal);
        }
        throw new JSONException("can not cast to short, value : " + value);
    }
	
	/**
     * Object ---> Date
     * @param value
     * @param format
     * @return
     */
    public static Date castToDate(Object value, String format){
        if(value == null){
            return null;
        }
        if(value instanceof Date){ // 使用頻率最高的,應優先處理
            return (Date) value;
        }
        if(value instanceof Calendar){
            return ((Calendar) value).getTime();
        }
        long longValue = -1;
        if(value instanceof Number){
            // longValue表示毫秒值
            longValue = ((Number) value).longValue();
            return new Date(longValue);
        }
        if(value instanceof String){
            // 處理字串(主要)
            String strVal = (String) value;
            JSONScanner dateLexer = new JSONScanner(strVal);
            try{
                // 反序列化為Calendar物件(後面介紹)
                if(dateLexer.scanISO8601DateIfMatch(false)){
                    Calendar calendar = dateLexer.getCalendar();
                    return calendar.getTime();
                }
            } finally{
                dateLexer.close();
            }
            // 處理/Date(1400046388387)/
            if(strVal.startsWith("/Date(") && strVal.endsWith(")/")){
                strVal = strVal.substring(6, strVal.length() - 2);
            }
            if(strVal.indexOf('-') != -1){
                if (format == null) {
                    // 如果沒有指定format,通過解析值判斷
                    if (strVal.length() == JSON.DEFFAULT_DATE_FORMAT.length()
                            || (strVal.length() == 22 && JSON.DEFFAULT_DATE_FORMAT.equals("yyyyMMddHHmmssSSSZ"))) {
                        format = JSON.DEFFAULT_DATE_FORMAT;
                    } else if (strVal.length() == 10) {
                        format = "yyyy-MM-dd";
                    } else if (strVal.length() == "yyyy-MM-dd HH:mm:ss".length()) {
                        format = "yyyy-MM-dd HH:mm:ss";
                    } else if (strVal.length() == 29
                            && strVal.charAt(26) == ':'
                            && strVal.charAt(28) == '0') {
                        format = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX";
                    } else {
                        format = "yyyy-MM-dd HH:mm:ss.SSS";
                    }
                }

                SimpleDateFormat dateFormat = new SimpleDateFormat(format, JSON.defaultLocale);
                dateFormat.setTimeZone(JSON.defaultTimeZone);
                try{
                    // 解析時間
                    return dateFormat.parse(strVal);
                } catch(ParseException e){
                    throw new JSONException("can not cast to Date, value : " + strVal);
                }
            }
            if(strVal.length() == 0){
                return null;
            }
            longValue = Long.parseLong(strVal);
        }
        if(longValue < 0){
            // 處理oracle時間型別
            Class<?> clazz = value.getClass();
            if("oracle.sql.TIMESTAMP".equals(clazz.getName())){
                if(oracleTimestampMethod == null && !oracleTimestampMethodInited){
                    try{
                        oracleTimestampMethod = clazz.getMethod("toJdbc");
                    } catch(NoSuchMethodException e){
                        // skip
                    } finally{
                        oracleTimestampMethodInited = true;
                    }
                }
                Object result;
                try{
                    result = oracleTimestampMethod.invoke(value);
                } catch(Exception e){
                    throw new JSONException("can not cast oracle.sql.TIMESTAMP to Date", e);
                }
                return (Date) result;
            }
            if("oracle.sql.DATE".equals(clazz.getName())){
                if(oracleDateMethod == null && !oracleDateMethodInited){
                    try{
                        oracleDateMethod = clazz.getMethod("toJdbc");
                    } catch(NoSuchMethodException e){
                        // skip
                    } finally{
                        oracleDateMethodInited = true;
                    }
                }
                Object result;
                try{
                    result = oracleDateMethod.invoke(value);
                } catch(Exception e){
                    throw new JSONException("can not cast oracle.sql.DATE to Date", e);
                }
                return (Date) result;
            }
            throw new JSONException("can not cast to Date, value : " + value);
        }
        return new Date(longValue);
    }

    /**
     * 複雜型別轉換
     * @param obj 需要轉換的物件
     * @param clazz 轉換型別
     * @param config 解析配置物件
     * @param <T>
     * @return
     */
    @SuppressWarnings({"unchecked", "rawtypes"})
    public static <T> T cast(Object obj, Class<T> clazz, ParserConfig config){
        if(obj == null){
            // 如果需要解析的物件為null,返回預設值
            if(clazz == int.class){
                return (T) Integer.valueOf(0);
            } else if(clazz == long.class){
                return (T) Long.valueOf(0);
            } else if(clazz == short.class){
                return (T) Short.valueOf((short) 0);
            } else if(clazz == byte.class){
                return (T) Byte.valueOf((byte) 0);
            } else if(clazz == float.class){
                return (T) Float.valueOf(0);
            } else if(clazz == double.class){
                return (T) Double.valueOf(0);
            } else if(clazz == boolean.class){
                return (T) Boolean.FALSE;
            }
            return null;
        }
        if(clazz == null){
            throw new IllegalArgumentException("clazz is null");
        }
        // 型別相同
        if(clazz == obj.getClass()){
            return (T) obj;
        }
        if(obj instanceof Map){
            if(clazz == Map.class){
                return (T) obj;
            }
            Map map = (Map) obj;
            if(clazz == Object.class && !map.containsKey(JSON.DEFAULT_TYPE_KEY)){
                return (T) obj;
            }
			// 重點說明
            return castToJavaBean((Map<String,Object>) obj, clazz, config);
        }
        if(clazz.isArray()){
            if(obj instanceof Collection){
                // 集合 ---> array
                Collection collection = (Collection) obj;
                int index = 0;
                Object array = Array.newInstance(clazz.getComponentType(), collection.size());
                for(Object item : collection){
                    // 迴圈新增
                    Object value = cast(item, clazz.getComponentType(), config);
                    Array.set(array, index, value);
                    index++;
                }
                return (T) array;
            }
            if(clazz == byte[].class){
                return (T) castToBytes(obj);
            }
        }
        /**
         * Class1.isAssignableFrom(Class2)  ① 判斷Class1和Class2是否相同。②Class1是否是Class2的父類或者介面。
         */
        if(clazz.isAssignableFrom(obj.getClass())){
            return (T) obj;
        }
        // 常見型別強轉
        if(clazz == boolean.class || clazz == Boolean.class){
            return (T) castToBoolean(obj);
        }
        if(clazz == byte.class || clazz == Byte.class){
            return (T) castToByte(obj);
        }
        if(clazz == char.class || clazz == Character.class){
            return (T) castToChar(obj);
        }
        if(clazz == short.class || clazz == Short.class){
            return (T) castToShort(obj);
        }
        if(clazz == int.class || clazz == Integer.class){
            return (T) castToInt(obj);
        }
        if(clazz == long.class || clazz == Long.class){
            return (T) castToLong(obj);
        }
        if(clazz == float.class || clazz == Float.class){
            return (T) castToFloat(obj);
        }
        if(clazz == double.class || clazz == Double.class){
            return (T) castToDouble(obj);
        }
        if(clazz == String.class){
            return (T) castToString(obj);
        }
        if(clazz == BigDecimal.class){
            return (T) castToBigDecimal(obj);
        }
        if(clazz == BigInteger.class){
            return (T) castToBigInteger(obj);
        }
        if(clazz == Date.class){
            return (T) castToDate(obj);
        }
        if(clazz == java.sql.Date.class){
            return (T) castToSqlDate(obj);
        }
        if(clazz == java.sql.Time.class){
            return (T) castToSqlTime(obj);
        }
        if(clazz == java.sql.Timestamp.class){
            return (T) castToTimestamp(obj);
        }
        if(clazz.isEnum()){
            return (T) castToEnum(obj, clazz, config);
        }
        if(Calendar.class.isAssignableFrom(clazz)){
            // Calendar
            Date date = castToDate(obj);
            Calendar calendar;
            if(clazz == Calendar.class){
                calendar = Calendar.getInstance(JSON.defaultTimeZone, JSON.defaultLocale);
            } else{
                try{
                    calendar = (Calendar) clazz.newInstance();
                } catch(Exception e){
                    throw new JSONException("can not cast to : " + clazz.getName(), e);
                }
            }
            calendar.setTime(date);
            return (T) calendar;
        }

        String className = clazz.getName();
        if(className.equals("javax.xml.datatype.XMLGregorianCalendar")){
            // XMLGregorianCalendar
            Date date = castToDate(obj);
            Calendar calendar = Calendar.getInstance(JSON.defaultTimeZone, JSON.defaultLocale);
            calendar.setTime(date);
            return (T) CalendarCodec.instance.createXMLGregorianCalendar(calendar);
        }

        if(obj instanceof String){
            String strVal = (String) obj;
            if(strVal.length() == 0 //
                    || "null".equals(strVal) //
                    || "NULL".equals(strVal)){
                return null;
            }
            if(clazz == java.util.Currency.class){
                // 類代表貨幣
                return (T) java.util.Currency.getInstance(strVal);
            }
            if(clazz == java.util.Locale.class){
                return (T) toLocale(strVal);
            }

            if (className.startsWith("java.time.")) {
                String json = JSON.toJSONString(strVal);
                return JSON.parseObject(json, clazz);
            }
        }
        throw new JSONException("can not cast to : " + clazz.getName());
    }
	
    /**
     *
     * @param map 屬性-->屬性值
     * @param clazz 轉換之後的class物件
     * @param config 解析配置物件
     * @param <T>
     * @return
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T castToJavaBean(Map<String,Object> map, Class<T> clazz, ParserConfig config){
        try{
            /**
             * StackTraceElement:
             *     private String declaringClass;
             *     private String methodName;
             *     private String fileName;
             *     private int    lineNumber;
             */
            if(clazz == StackTraceElement.class){
                String declaringClass = (String) map.get("className");
                String methodName = (String) map.get("methodName");
                String fileName = (String) map.get("fileName");
                int lineNumber;
                {
                    Number value = (Number) map.get("lineNumber");
                    if(value == null){
                        lineNumber = 0;
                    } else{
                        lineNumber = value.intValue();
                    }
                }
                return (T) new StackTraceElement(declaringClass, methodName, fileName, lineNumber);
            }

            {
                Object iClassObject = map.get(JSON.DEFAULT_TYPE_KEY);
                if(iClassObject instanceof String){
                    String className = (String) iClassObject;
                    Class<?> loadClazz;
                    if(config == null){
                        config = ParserConfig.global;
                    }
                    loadClazz = config.checkAutoType(className, null);
                    if(loadClazz == null){
                        throw new ClassNotFoundException(className + " not found");
                    }
                    if(!loadClazz.equals(clazz)){
                        return (T) castToJavaBean(map, loadClazz, config);
                    }
                }
            }

            if(clazz.isInterface()){
                // 判斷是不是介面
                JSONObject object;
                if(map instanceof JSONObject){
                    object = (JSONObject) map;
                } else{
                    object = new JSONObject(map);
                }
                if(config == null){
                    config = ParserConfig.getGlobalInstance();
                }
                // 反序列化物件
                ObjectDeserializer deserializer = config.getDeserializers().get(clazz);
                if(deserializer != null){
                    String json = JSON.toJSONString(object);
                    return (T) JSON.parseObject(json, clazz);
                }
                //  newProxyInstance方法用來返回一個代理物件,這個方法總共有3個引數,ClassLoader loader用來指明生成代理物件使用哪個類裝載器,
                // Class<?>[] interfaces用來指明生成哪個物件的代理物件,通過介面指定,InvocationHandler h用來指明產生的這個代理物件要做什麼事情
                // 比如修改物件方法行為
                return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                        new Class<?>[]{clazz}, object);
            }

            if(clazz == Locale.class){
                Object arg0 = map.get("language");
                Object arg1 = map.get("country");
                if(arg0 instanceof String){
                    String language = (String) arg0;
                    if(arg1 instanceof String){
                        String country = (String) arg1;
                        return (T) new Locale(language, country);
                    } else if(arg1 == null){
                        return (T) new Locale(language);
                    }
                }
            }

            if (clazz == String.class && map instanceof JSONObject) {
                return (T) map.toString();
            }

            if (clazz == LinkedHashMap.class && map instanceof JSONObject) {
                // 轉換為LinkedHashMap
                JSONObject jsonObject = (JSONObject) map;
                Map innerMap = jsonObject.getInnerMap();
                if (innerMap instanceof LinkedHashMap) {
                    return (T) innerMap;
                } else {
                    LinkedHashMap linkedHashMap = new LinkedHashMap();
                    linkedHashMap.putAll(innerMap);
                }
            }

            if (config == null) {
                // 預設解析配置
                config = ParserConfig.getGlobalInstance();
            }

            JavaBeanDeserializer javaBeanDeser = null;
            // 反序列化操作例項
            ObjectDeserializer deserizer = config.getDeserializer(clazz);
            if (deserizer instanceof JavaBeanDeserializer) {
                javaBeanDeser = (JavaBeanDeserializer) deserizer;
            }

            if(javaBeanDeser == null){
                throw new JSONException("can not get javaBeanDeserializer. " + clazz.getName());
            }
            // 建立物件(後面介紹)
            return (T) javaBeanDeser.createInstance(map, config);
        } catch(Exception e){
            throw new JSONException(e.getMessage(), e);
        }
    }	


    /**
     * 載入類
     * @param className 類全名
     * @param classLoader 使用的型別載入器
     * @param cache 是否加入到快取集合中
     * @return
     */
    public static Class<?> loadClass(String className, ClassLoader classLoader, boolean cache) {
        if(className == null || className.length() == 0){
            return null;
        }
        // 常見型別取快取
        Class<?> clazz = mappings.get(className);
        if(clazz != null){
            return clazz;
        }
        if(className.charAt(0) == '['){
            // 陣列
            Class<?> componentType = loadClass(className.substring(1), classLoader);
            return Array.newInstance(componentType, 0).getClass();
        }
        if(className.startsWith("L") && className.endsWith(";")){
            // 普通物件
            String newClassName = className.substring(1, className.length() - 1);
            return loadClass(newClassName, classLoader);
        }
        try{
            if(classLoader != null){
                clazz = classLoader.loadClass(className);
                if (cache) {
                    // 新增到快取中
                    mappings.put(className, clazz);
                }
                return clazz;
            }
        } catch(Throwable e){
            e.printStackTrace();
            // skip
        }
        try{
            ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
            if(contextClassLoader != null && contextClassLoader != classLoader){
                clazz = contextClassLoader.loadClass(className);
                if (cache) {
                    // 新增到快取中
                    mappings.put(className, clazz);
                }
                return clazz;
            }
        } catch(Throwable e){
            // skip
        }
        try{
            // class.forName()除了將類的.class檔案載入到jvm中之外,執行類中的static塊。而classLoader只是將.class檔案載入到jvm中
            // 反射中Class.forName()和ClassLoader.loadClass()的區別 參考:https://www.cnblogs.com/zabulon/p/5826610.html
            clazz = Class.forName(className);
            mappings.put(className, clazz);
            return clazz;
        } catch(Throwable e){
            // skip
        }
        return clazz;
    }

	
	/**
     * 獲取註解(會查詢註解上的註解)
     */
    public static <A extends Annotation> A getAnnotation(Class<?> clazz, Class<A> annotationClass){
        // Class上查詢指定的註解
        A a = clazz.getAnnotation(annotationClass);
        if (a != null){
            return a;
        }
        // 獲取所有的註解
        if(clazz.getAnnotations().length > 0){
            for(Annotation annotation : clazz.getAnnotations()){
                // 判斷註解的註解上是不是存在指定的註解
                a = annotation.annotationType().getAnnotation(annotationClass);
                if(a != null){
                    return a;
                }
            }
        }
        return null;
    }

3.體會

3.1 kotlin我沒有接觸過,所以和這個相關的原始碼未做解析

3.2 在本工具類中也使用了空間換時間的方式,即addBaseClassMappings方法在載入類時直接將常見的類加入到快取中。

3.3 這個工具類可以作為專案中型別轉換的參考,但是有些因為考慮較複雜,在真實的專案中由於特定條件的約束,不一定全部需要考慮。比如:castToDate,在實際專案中可以考慮適當的簡化。

4.說明

4.1 本文是原創作品,如果需要轉載請說明轉載位置

4.2 本人是一個小菜鳥,如果上面的觀點或者解析有誤的地方,請大家及時指出,謝謝^_^