引言
TypeUtils
是 FastJSON 库中的一个重要工具类,主要用于处理各种类型的转换和解析。FastJSON 是阿里巴巴开源的一个高性能 JSON 解析和生成库,广泛应用于 Java 应用中。本文将详细介绍 TypeUtils
类的主要功能和实现细节,帮助读者更好地理解和使用这一工具类。
1. 类概述
TypeUtils
类提供了多种静态方法,用于处理不同类型之间的转换、反射操作以及一些辅助功能。这些方法在 FastJSON 的序列化和反序列化过程中起着至关重要的作用。
2. 主要功能
2.1 类型转换
TypeUtils
提供了多种类型转换方法,用于将对象转换为目标类型。这些方法包括但不限于:
castToXXX
系列方法:将对象转换为特定的基本类型(如int
,long
,double
等)。convertValue
方法:将对象转换为指定的目标类型。
示例代码
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
:获取类的所有方法。
示例代码
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
:获取类型的原始类。
示例代码
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
还提供了一些辅助功能,如日期和时间的解析、字符串处理等。
示例代码
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
类的 getDeclaredField
、getDeclaredMethods
等方法来获取类的字段和方法信息。为了处理继承关系,TypeUtils
递归地查找父类的字段和方法。
3.3 类型解析
类型解析方法主要通过 ParameterizedType
和 GenericArrayType
等接口来处理泛型和数组类型。TypeUtils
提供了多种辅助方法来获取泛型的实际类型和原始类。
4. 使用场景
TypeUtils
类在 FastJSON 的序列化和反序列化过程中扮演着重要角色。以下是一些常见的使用场景:
- 对象转换:将 JSON 字符串转换为 Java 对象时,需要将不同的 JSON 值转换为对应的 Java 类型。
- 反射操作:在处理复杂的对象结构时,需要通过反射获取类的字段和方法信息。
- 类型解析:在处理泛型和集合类型时,需要解析类型参数以确保正确性。
5. 结论
TypeUtils
类是 FastJSON 库中的一个重要工具类,提供了丰富的类型转换、反射操作和类型解析功能。通过本文的介绍,希望读者能够更好地理解和使用 TypeUtils
类,从而在实际开发中更加高效地处理各种类型转换和反射操作。
附录:相关代码片段
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;}
}