Gsonソース分析(一)
10326 ワード
Json解析はネットワーク通信において重要なデータ解析フレームワークである.GsonとFastJsonは最もよく使われる2つのJson解析フレームワークである.この章では主にGsonの原理を紹介する.Gsonの典型的な使用例は以下の通りである.
GsonのfromJson()メソッドのソースコードは次のとおりです.
以上のようにfromJson()メソッドは主に3つのステップに分けられる:1 Type Tokenを取得し,2 Type Adapterを取得し,3 Type Adapterを用いて解析する.以下、この3つのステップに従って分析します.(1)TypeToken TypeTokenのget()メソッドのソースコードは以下の通りである.
TypeTokenは解析対象データのTypeタイプを保存している.(2)TypeAdapter TypeAdapterはgetAdapter()メソッドで取得する.getAdapter()メソッドのソースコードは次のとおりです.
TypeTokenCacheにTypeToken対応のTypeAdapterがない場合、factoriesから対応するTypeAdapterを検索します.factoriesがType Adapterを検索する基準は、Type AdapterFactoryのcreate()メソッドが空でないことを返します.factoriesの初期化はGsonの構造方法において以下の通りである.
上記factoriesにはGsonが解析できるすべてのデータフォーマットが含まれています.以下STRING_FACTORYを例に説明します.
newFactory()メソッドが返すTypeAdapterFactoryのcreate()メソッドは、typeの一貫性を検証するために1つのことをしました.つまり、処理するデータ型がStringの場合はType Adapter、そうでなければnullを返します.Stringタイプに対応するType Adapterのソースコードは以下の通りです.
Gson解析については,簡単な流れが紹介されている.解析の観点から分析を重視します.
String jsonString = "{\"name\":\"renyiguang\"}";
Gson gson = new Gson();
TestModel testModel = gson.fromJson(jsonString, TestModel.class);
GsonのfromJson()メソッドのソースコードは次のとおりです.
public T fromJson(String json, Class classOfT) throws JsonSyntaxException {
Object object = fromJson(json, (Type) classOfT);
return Primitives.wrap(classOfT).cast(object);
}
public T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
JsonReader jsonReader = newJsonReader(json);
T object = (T) fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
return object;
}
public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
reader.peek();
isEmpty = false;
TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);//1 TypeToken
TypeAdapter typeAdapter = getAdapter(typeToken);//2 TypeAdapter
T object = typeAdapter.read(reader);//3
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
throw new JsonSyntaxException(e);
} finally {
reader.setLenient(oldLenient);
}
}
以上のようにfromJson()メソッドは主に3つのステップに分けられる:1 Type Tokenを取得し,2 Type Adapterを取得し,3 Type Adapterを用いて解析する.以下、この3つのステップに従って分析します.(1)TypeToken TypeTokenのget()メソッドのソースコードは以下の通りである.
public static TypeToken> get(Type type) {
return new TypeToken
TypeTokenは解析対象データのTypeタイプを保存している.(2)TypeAdapter TypeAdapterはgetAdapter()メソッドで取得する.getAdapter()メソッドのソースコードは次のとおりです.
public TypeAdapter getAdapter(TypeToken type) {
TypeAdapter> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);// TypeAdapter
if (cached != null) {
return (TypeAdapter) cached;
}
Map, FutureTypeAdapter>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap, FutureTypeAdapter>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter call = new FutureTypeAdapter();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {// factories
TypeAdapter candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
TypeTokenCacheにTypeToken対応のTypeAdapterがない場合、factoriesから対応するTypeAdapterを検索します.factoriesがType Adapterを検索する基準は、Type AdapterFactoryのcreate()メソッドが空でないことを返します.factoriesの初期化はGsonの構造方法において以下の通りである.
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
final Map> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy,
List typeAdapterFactories) {
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
this.excluder = excluder;
this.fieldNamingStrategy = fieldNamingStrategy;
this.serializeNulls = serializeNulls;
this.generateNonExecutableJson = generateNonExecutableGson;
this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting;
this.lenient = lenient;
List factories = new ArrayList();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// user's type adapters
factories.addAll(typeAdapterFactories);// TypeAdapterFactory
// type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
TypeAdapter longAdapter = longAdapter(longSerializationPolicy);
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
factories.add(TypeAdapters.newFactory(double.class, Double.class,
doubleAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.newFactory(float.class, Float.class,
floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
factories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
factories.add(TypeAdapters.URL_FACTORY);
factories.add(TypeAdapters.URI_FACTORY);
factories.add(TypeAdapters.UUID_FACTORY);
factories.add(TypeAdapters.CURRENCY_FACTORY);
factories.add(TypeAdapters.LOCALE_FACTORY);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);
factories.add(TimeTypeAdapter.FACTORY);
factories.add(SqlDateTypeAdapter.FACTORY);
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
factories.add(TypeAdapters.CLASS_FACTORY);
// type adapters for composite and user-defined types
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this.factories = Collections.unmodifiableList(factories);
}
上記factoriesにはGsonが解析できるすべてのデータフォーマットが含まれています.以下STRING_FACTORYを例に説明します.
public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
public static TypeAdapterFactory newFactory(
final Class type, final TypeAdapter typeAdapter) {
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override public TypeAdapter create(Gson gson, TypeToken typeToken) {
return typeToken.getRawType() == type ? (TypeAdapter) typeAdapter : null;
}
@Override public String toString() {
return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]";
}
};
}
newFactory()メソッドが返すTypeAdapterFactoryのcreate()メソッドは、typeの一貫性を検証するために1つのことをしました.つまり、処理するデータ型がStringの場合はType Adapter、そうでなければnullを返します.Stringタイプに対応するType Adapterのソースコードは以下の通りです.
public static final TypeAdapter STRING = new TypeAdapter() {
@Override
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
return Boolean.toString(in.nextBoolean());
}
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
out.value(value);
}
};
Gson解析については,簡単な流れが紹介されている.解析の観点から分析を重視します.