fastjson原始碼解析(2)-工具類TypeUtils
阿新 • • 發佈:2019-01-03
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 本人是一個小菜鳥,如果上面的觀點或者解析有誤的地方,請大家及時指出,謝謝^_^