引言
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
类的 getDeclaredField
、getDeclaredMethods
等方法来获取类的字段和方法信息。为了处理继承关系,TypeUtils
递归地查找父类的字段和方法。
3.3 类型解析
类型解析方法主要通过 ParameterizedType
和 GenericArrayType
等接口来处理泛型和数组类型。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;
}
}