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 本人是一个小菜鸟,如果上面的观点或者解析有误的地方,请大家及时指出,谢谢^_^


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值