【工具类】理解 TypeUtils 类:深入解析 FastJSON 的类型转换工具

引言

TypeUtils 是 FastJSON 库中的一个重要工具类,主要用于处理各种类型的转换和解析。FastJSON 是阿里巴巴开源的一个高性能 JSON 解析和生成库,广泛应用于 Java 应用中。本文将详细介绍 TypeUtils 类的主要功能和实现细节,帮助读者更好地理解和使用这一工具类。

1. 类概述

TypeUtils 类提供了多种静态方法,用于处理不同类型之间的转换、反射操作以及一些辅助功能。这些方法在 FastJSON 的序列化和反序列化过程中起着至关重要的作用。

2. 主要功能
2.1 类型转换

TypeUtils 提供了多种类型转换方法,用于将对象转换为目标类型。这些方法包括但不限于:

  • castToXXX 系列方法:将对象转换为特定的基本类型(如 int, long, double 等)。
  • convertValue 方法:将对象转换为指定的目标类型。
示例代码
java 复制代码
public static Integer castToInt(Object value) {
    if (value == null) {
        return null;
    }
    if (value instanceof Integer) {
        return (Integer) value;
    }
    if (value instanceof Number) {
        return ((Number) value).intValue();
    }
    if (value instanceof String) {
        String strVal = (String) value;
        if (strVal.length() == 0 || "null".equals(strVal)) {
            return null;
        }
        return Integer.parseInt(strVal);
    }
    throw new JSONException("can not cast to int, value : " + value);
}
2.2 反射操作

TypeUtils 提供了一系列反射相关的操作,用于获取类的字段、方法等信息。这些方法包括:

  • getField:获取类的字段。
  • getDeclaredFields:获取类的所有声明字段。
  • getMethods:获取类的所有方法。
示例代码
java 复制代码
public static Field getField(Class<?> clazz, String fieldName) {
    if (clazz == null) {
        return null;
    }
    try {
        return clazz.getDeclaredField(fieldName);
    } catch (NoSuchFieldException e) {
        Class<?> superClass = clazz.getSuperclass();
        if (superClass != null) {
            return getField(superClass, fieldName);
        }
    }
    return null;
}
2.3 类型解析

TypeUtils 提供了多种类型解析方法,用于处理泛型、数组、集合等复杂类型的解析。这些方法包括:

  • getCollectionItemType:获取集合类型的元素类型。
  • getActualType:获取泛型的实际类型。
  • getRawClass:获取类型的原始类。
示例代码
java 复制代码
public static Class<?> getCollectionItemType(Type fieldType) {
    if (fieldType instanceof ParameterizedType) {
        ParameterizedType parameterizedType = (ParameterizedType) fieldType;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        if (actualTypeArguments.length == 1) {
            return getRawClass(actualTypeArguments[0]);
        }
    }
    return Object.class;
}
2.4 辅助功能

TypeUtils 还提供了一些辅助功能,如日期和时间的解析、字符串处理等。

示例代码
java 复制代码
public static java.sql.Timestamp castToTimestamp(Object value) {
    if (value == null) {
        return null;
    }
    if (value instanceof java.sql.Timestamp) {
        return (java.sql.Timestamp) value;
    }
    if (value instanceof Date) {
        return new java.sql.Timestamp(((Date) value).getTime());
    }
    if (value instanceof String) {
        String strVal = (String) value;
        long longValue = 0;
        if (strVal.length() == 23) {
            int year = num(strVal.charAt(0), strVal.charAt(1), strVal.charAt(2), strVal.charAt(3));
            int month = num(strVal.charAt(5), strVal.charAt(6));
            int day = num(strVal.charAt(8), strVal.charAt(9));
            int hour = num(strVal.charAt(11), strVal.charAt(12));
            int minute = num(strVal.charAt(14), strVal.charAt(15));
            int second = num(strVal.charAt(17), strVal.charAt(18));
            int nanos = num(strVal.charAt(20), strVal.charAt(21), strVal.charAt(22), strVal.charAt(23), strVal.charAt(24), strVal.charAt(25), strVal.charAt(26), strVal.charAt(27), strVal.charAt(28));
            return new java.sql.Timestamp(year - 1900, month - 1, day, hour, minute, second, nanos);
        }
        if (isNumber(strVal)) {
            longValue = Long.parseLong(strVal);
        } else {
            JSONScanner scanner = new JSONScanner(strVal);
            if (scanner.scanISO8601DateIfMatch(false)) {
                longValue = scanner.getCalendar().getTime().getTime();
            } else {
                throw new JSONException("can not cast to Timestamp, value : " + strVal);
            }
        }
        if (longValue <= 0) {
            throw new JSONException("can not cast to Timestamp, value : " + value);
        }
        return new java.sql.Timestamp(longValue);
    }
    throw new JSONException("can not cast to Timestamp, value : " + value);
}
3. 实现细节
3.1 类型转换

类型转换方法主要通过 instanceof 操作符和 Class 类的方法来判断对象的类型,并进行相应的转换。对于复杂的类型转换,如日期和时间的解析,TypeUtils 使用了正则表达式和 JSONScanner 等工具类来处理。

3.2 反射操作

反射操作主要通过 Class 类的 getDeclaredFieldgetDeclaredMethods 等方法来获取类的字段和方法信息。为了处理继承关系,TypeUtils 递归地查找父类的字段和方法。

3.3 类型解析

类型解析方法主要通过 ParameterizedTypeGenericArrayType 等接口来处理泛型和数组类型。TypeUtils 提供了多种辅助方法来获取泛型的实际类型和原始类。

4. 使用场景

TypeUtils 类在 FastJSON 的序列化和反序列化过程中扮演着重要角色。以下是一些常见的使用场景:

  • 对象转换:将 JSON 字符串转换为 Java 对象时,需要将不同的 JSON 值转换为对应的 Java 类型。
  • 反射操作:在处理复杂的对象结构时,需要通过反射获取类的字段和方法信息。
  • 类型解析:在处理泛型和集合类型时,需要解析类型参数以确保正确性。
5. 结论

TypeUtils 类是 FastJSON 库中的一个重要工具类,提供了丰富的类型转换、反射操作和类型解析功能。通过本文的介绍,希望读者能够更好地理解和使用 TypeUtils 类,从而在实际开发中更加高效地处理各种类型转换和反射操作。

附录:相关代码片段
java 复制代码
public class TypeUtils {
    private static final Pattern NUMBER_WITH_TRAILING_ZEROS_PATTERN = Pattern.compile("\\.0*$");
    public static boolean compatibleWithJavaBean = false;

    public static Integer castToInt(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Integer) {
            return (Integer) value;
        }
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        if (value instanceof String) {
            String strVal = (String) value;
            if (strVal.length() == 0 || "null".equals(strVal)) {
                return null;
            }
            return Integer.parseInt(strVal);
        }
        throw new JSONException("can not cast to int, value : " + value);
    }

    public static Field getField(Class<?> clazz, String fieldName) {
        if (clazz == null) {
            return null;
        }
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null) {
                return getField(superClass, fieldName);
            }
        }
        return null;
    }

    public static Class<?> getCollectionItemType(Type fieldType) {
        if (fieldType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) fieldType;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            if (actualTypeArguments.length == 1) {
                return getRawClass(actualTypeArguments[0]);
            }
        }
        return Object.class;
    }

    public static java.sql.Timestamp castToTimestamp(Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof java.sql.Timestamp) {
            return (java.sql.Timestamp) value;
        }
        if (value instanceof Date) {
            return new java.sql.Timestamp(((Date) value).getTime());
        }
        if (value instanceof String) {
            String strVal = (String) value;
            long longValue = 0;
            if (strVal.length() == 23) {
                int year = num(strVal.charAt(0), strVal.charAt(1), strVal.charAt(2), strVal.charAt(3));
                int month = num(strVal.charAt(5), strVal.charAt(6));
                int day = num(strVal.charAt(8), strVal.charAt(9));
                int hour = num(strVal.charAt(11), strVal.charAt(12));
                int minute = num(strVal.charAt(14), strVal.charAt(15));
                int second = num(strVal.charAt(17), strVal.charAt(18));
                int nanos = num(strVal.charAt(20), strVal.charAt(21), strVal.charAt(22), strVal.charAt(23), strVal.charAt(24), strVal.charAt(25), strVal.charAt(26), strVal.charAt(27), strVal.charAt(28));
                return new java.sql.Timestamp(year - 1900, month - 1, day, hour, minute, second, nanos);
            }
            if (isNumber(strVal)) {
                longValue = Long.parseLong(strVal);
            } else {
                JSONScanner scanner = new JSONScanner(strVal);
                if (scanner.scanISO8601DateIfMatch(false)) {
                    longValue = scanner.getCalendar().getTime().getTime();
                } else {
                    throw new JSONException("can not cast to Timestamp, value : " + strVal);
                }
            }
            if (longValue <= 0) {
                throw new JSONException("can not cast to Timestamp, value : " + value);
            }
            return new java.sql.Timestamp(longValue);
        }
        throw new JSONException("can not cast to Timestamp, value : " + value);
    }

    private static int num(char c0, char c1) {
        if (c0 >= '0' && c0 <= '9' && c1 >= '0' && c1 <= '9') {
            return (c0 - '0') * 10 + (c1 - '0');
        }
        return -1;
    }

    private static int num(char c0, char c1, char c2, char c3) {
        if (c0 >= '0' && c0 <= '9' && c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9' && c3 >= '0' && c3 <= '9') {
            return (c0 - '0') * 1000 + (c1 - '0') * 100 + (c2 - '0') * 10 + (c3 - '0');
        }
        return -1;
    }

    private static int num(char c0, char c1, char c2, char c3, char c4, char c5, char c6, char c7, char c8) {
        if (c0 >= '0' && c0 <= '9' && c1 >= '0' && c1 <= '9' && c2 >= '0' && c2 <= '9' && c3 >= '0' && c3 <= '9' && c4 >= '0' && c4 <= '9' && c5 >= '0' && c5 <= '9' && c6 >= '0' && c6 <= '9' && c7 >= '0' && c7 <= '9' && c8 >= '0' && c8 <= '9') {
            return (c0 - '0') * 100000000 + (c1 - '0') * 10000000 + (c2 - '0') * 1000000 + (c3 - '0') * 100000 + (c4 - '0') * 10000 + (c5 - '0') * 1000 + (c6 - '0') * 100 + (c7 - '0') * 10 + (c8 - '0');
        }
        return -1;
    }

    public static boolean isNumber(String str) {
        for (int i = 0; i < str.length(); ++i) {
            char ch = str.charAt(i);
            if (ch == '+' || ch == '-') {
                if (i != 0) {
                    return false;
                }
            } else if (ch < '0' || ch > '9') {
                return false;
            }
        }
        return true;
    }
}
相关推荐
许苑向上4 分钟前
最详细【Elasticsearch】Elasticsearch Java API + Spring Boot集成 实战入门(基础篇)
java·数据库·spring boot·elasticsearch
柳叶寒9 分钟前
医院信息化与智能化系统(17)
java·nacos·gateway·全栈·项目
首席架构师专栏10 分钟前
吊打面试官系列:final、finally、finalize 有什么区别?
java
hxj..20 分钟前
【算法】动态规划
java·算法·动态规划
世间万物皆对象33 分钟前
Java 基础教学:高级特性与实战-集合框架
java·开发语言
不爱吃米饭_37 分钟前
如何优雅处理异常?处理异常的原则
java·开发语言·spring boot
李少兄1 小时前
IntelliJ IDEA 中创建目录时 `.` 和 `/` 的区别
java·ide·intellij-idea
V+zmm101341 小时前
社区养老服务小程序ssm+论文源码调试讲解
java·服务器·前端·javascript·小程序·毕业设计·1024程序员节
李少兄1 小时前
如何在 IntelliJ IDEA 中调整 `Ctrl+/` 快捷键生成注释的位置
java·ide·intellij-idea
AiFlutter1 小时前
Java对接GraphQL
java·开发语言·graphql