今天在网上看代码时,发现项目使用了Gson,用于将json字符串转换成javaBean.
以前没使用过Gson,随即,简单入了个们,
想起fastjson也有将json字符串转换成javaBean的API,随即简单比较了下源码.
fastjson中的API如下:
/**
* @since 1.2.9
*/
public <T> T toJavaObject(Class<T> clazz) {
return TypeUtils.cast(this, clazz, ParserConfig.getGlobalInstance());
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <T> T cast(Object obj, Class<T> clazz, ParserConfig config) {
if (obj == null) {
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) {
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);
}
}
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) castToCharacter(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.Timestamp.class) {
return (T) castToTimestamp(obj);
}
if (clazz.isEnum()) {
return (T) castToEnum(obj, clazz, config);
}
if (Calendar.class.isAssignableFrom(clazz)) {
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;
}
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);
}
}
throw new JSONException("can not cast to : " + clazz.getName());
}
@SuppressWarnings({ "unchecked" })
public static <T> T castToJavaBean(Map<String, Object> map, Class<T> clazz, ParserConfig config) {
try {
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 = (Class<T>) loadClass(className);
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);
}
return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
new Class<?>[] { clazz }, object);
}
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");
}
return (T) javaBeanDeser.createInstance(map, config);
} catch (Exception e) {
throw new JSONException(e.getMessage(), e);
}
}
简单捋了一遍,看到代码中标黄的部分代码,可知,是利用反射原理来获得javaBean的.
如下,为Gson的demo:
1 package cn.code.gson; 2 3 import java.io.*; 4 5 import java.util.Map; 6 7 import com.google.gson.Gson; 8 import com.google.gson.GsonBuilder; 9 10 import cn.code.entity.Person; 11 12 /** 13 * Created by zq on 2017/6/16. 14 */ 15 public class GsonTest { 16 17 /** 18 * @param args 主函数形参 19 */ 20 public static void main(String[] args) { 21 Gson gson = new GsonBuilder().create(); 22 23 gson.toJson("Hello", System.out); 24 gson.toJson("123", System.out); 25 System.out.println(); 26 27 // try (Writer writer = new FileWriter("d:\gson.txt")) { 28 // gson.toJson("Hello", writer); 29 // gson.toJson("123", writer); 30 // } catch (IOException e) { 31 // e.printStackTrace(); 32 // } 33 FileInputStream fileInputStream = null; 34 35 try { 36 fileInputStream = new FileInputStream("d:\gson.txt"); 37 } catch (FileNotFoundException e) { 38 e.printStackTrace(); 39 } 40 41 Person person = getJavaBean(fileInputStream); 42 43 System.out.println(person); 44 } 45 46 /** 47 * 48 * @param fileInputStream 根据附件字节流 返回java类 49 * @return 50 */ 51 public static Person getJavaBean(FileInputStream fileInputStream) { 52 Gson gson = new GsonBuilder().create(); 53 Person person = null; 54 55 try (Reader reader = new InputStreamReader(fileInputStream)) { 56 person = gson.fromJson(reader, Person.class); 57 } catch (FileNotFoundException e) { 58 e.printStackTrace(); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } 62 63 return person; 64 } 65 } 66 67 68 //~ Formatted by Jindent --- http://www.jindent.com
Gson中使用了如下代码获取javaBean:
person = gson.fromJson(reader, Person.class);
源码如下(版本:2.2.4):
1 public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException { 2 JsonReader jsonReader = new JsonReader(json); 3 Object object = fromJson(jsonReader, classOfT); 4 assertFullConsumption(object, jsonReader); 5 return Primitives.wrap(classOfT).cast(object); 6 } 7 8 9 @SuppressWarnings("unchecked") 10 public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { 11 boolean isEmpty = true; 12 boolean oldLenient = reader.isLenient(); 13 reader.setLenient(true); 14 try { 15 reader.peek(); 16 isEmpty = false; 17 TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT); 18 TypeAdapter<T> typeAdapter = getAdapter(typeToken); 19 T object = typeAdapter.read(reader); 20 return object; 21 } catch (EOFException e) { 22 /* 23 * For compatibility with JSON 1.5 and earlier, we return null for empty 24 * documents instead of throwing. 25 */ 26 if (isEmpty) { 27 return null; 28 } 29 throw new JsonSyntaxException(e); 30 } catch (IllegalStateException e) { 31 throw new JsonSyntaxException(e); 32 } catch (IOException e) { 33 // TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException 34 throw new JsonSyntaxException(e); 35 } finally { 36 reader.setLenient(oldLenient); 37 } 38 }
以上版本中,Json和javabean之间依赖于各类的TypeAdapter(类型转换器集合)获得:
TypeAdapter<?> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
;
以下是版本1.6中的部分核心源码:
private <T> T fromJsonObject(Type typeOfT, JsonObject jsonObject, JsonDeserializationContext context) throws JsonParseException { JsonObjectDeserializationVisitor<T> visitor = new JsonObjectDeserializationVisitor<T>( jsonObject, typeOfT, navigatorFactory, objectConstructor, deserializers, context); ObjectNavigator on = navigatorFactory.create(new ObjectTypePair(null, typeOfT, true)); //适配器模式 on.accept(visitor); return visitor.getTarget(); } /** * Navigate all the fields of the specified object. If a field is null, it * does not get visited. */ public void accept(Visitor visitor) { TypeInfo objTypeInfo = new TypeInfo(objTypePair.type); if (exclusionStrategy.shouldSkipClass(objTypeInfo.getRawClass())) { return; } boolean visitedWithCustomHandler = visitor.visitUsingCustomHandler(objTypePair); if (!visitedWithCustomHandler) { Object obj = objTypePair.getObject(); Object objectToVisit = (obj == null) ? visitor.getTarget() : obj; if (objectToVisit == null) { return; } objTypePair.setObject(objectToVisit); visitor.start(objTypePair); try { if (objTypeInfo.isArray()) { visitor.visitArray(objectToVisit, objTypePair.type); } else if (objTypeInfo.getActualType() == Object.class && isPrimitiveOrString(objectToVisit)) { // TODO(Joel): this is only used for deserialization of "primitives" // we should rethink this!!! visitor.visitPrimitive(objectToVisit); objectToVisit = visitor.getTarget(); } else { visitor.startVisitingObject(objectToVisit); ObjectTypePair currObjTypePair = objTypePair.toMoreSpecificType(); Class<?> topLevelClass = new TypeInfo(currObjTypePair.type).getRawClass(); for (Class<?> curr = topLevelClass; curr != null && !curr.equals(Object.class); curr = curr.getSuperclass()) { if (!curr.isSynthetic()) { navigateClassFields(objectToVisit, curr, visitor); } } } } finally { visitor.end(objTypePair); } } }
private void navigateClassFields(Object obj, Class<?> clazz, Visitor visitor) {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field f : fields) { //遍历javabean 的field 赋值
FieldAttributes fieldAttributes = new FieldAttributes(clazz, f);
if (exclusionStrategy.shouldSkipField(fieldAttributes)
|| exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) {
continue; // skip
}
TypeInfo fieldTypeInfo = TypeInfoFactory.getTypeInfoForField(f, objTypePair.type);
Type declaredTypeOfField = fieldTypeInfo.getActualType();
boolean visitedWithCustomHandler =
visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj);
if (!visitedWithCustomHandler) {
if (fieldTypeInfo.isArray()) {
visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj);
} else {
visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj);
}
}
}
以上为粗略了解,甚至不算入门,有兴趣的小伙伴们可自行阅读源码.