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