從一個(gè)問題開始
假設(shè)有這么一個(gè)類:
- class MyObj {
-
- public final int x;
-
- public MyObj(int x) {
- this.x = x;
- }
-
- }
和下面的測試代碼:
- @Test
- public void gson() {
- MyObj obj = new Gson().fromJson("{\"x\":1}", MyObj.class);
- Assert.assertEquals(1, obj.x);
- }
那么GSON是通過什么樣的方式創(chuàng)建MyObj對象的呢?答案可能會出乎你的意料(至少出乎了我的意料)。
InstanceCreator和ObjectConstructor
經(jīng)過斷點(diǎn)調(diào)試或者閱讀源代碼不難發(fā)現(xiàn),GSON是使用ObjectConstructor來創(chuàng)建對象實(shí)例的,這點(diǎn)從代碼注釋里也能看的出來:
- /**
- * Defines a generic object construction factory. The purpose of this class
- * is to construct a default instance of a class that can be used for object
- * navigation while deserialization from its JSON representation.
- *
- * @author Inderjeet Singh
- * @author Joel Leitch
- */
- public interface ObjectConstructor<T> {
-
- /**
- * Returns a new instance.
- */
- public T construct();
- }
那么ObjectConstructor從何而來呢?答案在ConstructorConstructor里:
- public <T> ObjectConstructor<T> get(TypeToken<T> typeToken) {
- final Type type = typeToken.getType();
- final Class<? super T> rawType = typeToken.getRawType();
-
- // first try an instance creator
-
- @SuppressWarnings("unchecked") // types must agree
- final InstanceCreator<T> typeCreator = (InstanceCreator<T>) instanceCreators.get(type);
- if (typeCreator != null) {
- return new ObjectConstructor<T>() {
- public T construct() {
- return typeCreator.createInstance(type);
- }
- };
- }
-
- // Next try raw type match for instance creators
- @SuppressWarnings("unchecked") // types must agree
- final InstanceCreator<T> rawTypeCreator =
- (InstanceCreator<T>) instanceCreators.get(rawType);
- if (rawTypeCreator != null) {
- return new ObjectConstructor<T>() {
- public T construct() {
- return rawTypeCreator.createInstance(type);
- }
- };
- }
-
- ObjectConstructor<T> defaultConstructor = newDefaultConstructor(rawType);
- if (defaultConstructor != null) {
- return defaultConstructor;
- }
-
- ObjectConstructor<T> defaultImplementation = newDefaultImplementationConstructor(type, rawType);
- if (defaultImplementation != null) {
- return defaultImplementation;
- }
-
- // finally try unsafe
- return newUnsafeAllocator(type, rawType);
- }
代碼看起來很復(fù)雜,但實(shí)際上井然有序:
- 如果我們(通過GsonBuilder)注冊過InstanceCreator,則交給InstanceCreator來創(chuàng)建實(shí)例
- 如果類有默認(rèn)構(gòu)造函數(shù),則通過反射調(diào)用默認(rèn)構(gòu)造函數(shù)創(chuàng)建實(shí)例
- 如果想要創(chuàng)建List或Map等接口的實(shí)例,則走這里
- 否則交給神秘的UnsafeAllocator來收場
第一和第三種情況暫不考慮,下面來分析第二和第四種情況。
有默認(rèn)構(gòu)造函數(shù)的情況
按照前面的分析,這種情況GSON是通過調(diào)用默認(rèn)構(gòu)造函數(shù)來創(chuàng)建對象實(shí)例的,讓我們證明這一點(diǎn):
- class MyObj {
-
- public final int x;
-
- public MyObj() {
- throw new RuntimeException("!!!"); // <---
- }
-
- }
- @Test(expected = RuntimeException.class) // <---
- public void gson() {
- new Gson().fromJson("{\"x\":1}", MyObj.class);
- }
測試通過!
沒有默認(rèn)構(gòu)造函數(shù)的情況
還是通過代碼來證明這一點(diǎn):
- class MyObj {
-
- public final int x;
-
- public MyObj(int x) { // <---
- throw new RuntimeException("!!!");
- }
-
- }
- @Test
- public void gson() {
- MyObj obj = new Gson().fromJson("{\"x\":1}", MyObj.class);
- Assert.assertEquals(1, obj.x);
- }
測試通過!
UnsafeAllocator
現(xiàn)在讓我們一睹UnsafeAllocator的風(fēng)采:
- /**
- * Do sneaky things to allocate objects without invoking their constructors.
- *
- * @author Joel Leitch
- * @author Jesse Wilson
- */
- public abstract class UnsafeAllocator {
- public abstract <T> T newInstance(Class<T> c) throws Exception;
-
- public static UnsafeAllocator create() {
- // try JVM
- // public class Unsafe {
- // public Object allocateInstance(Class<?> type);
- // }
- try {
- Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
- Field f = unsafeClass.getDeclaredField("theUnsafe");
- f.setAccessible(true);
- final Object unsafe = f.get(null);
- final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);
- return new UnsafeAllocator() {
- @Override
- @SuppressWarnings("unchecked")
- public <T> T newInstance(Class<T> c) throws Exception {
- return (T) allocateInstance.invoke(unsafe, c);
- }
- };
- } catch (Exception ignored) {
- }
-
- ...
-
- // give up
- return new UnsafeAllocator() {
- @Override
- public <T> T newInstance(Class<T> c) {
- throw new UnsupportedOperationException("Cannot allocate " + c);
- }
- };
- }
- }
去掉反射后,代碼看起來大概是這樣:
- public abstract class UnsafeAllocator {
- public abstract <T> T newInstance(Class<T> c) throws Exception;
-
- public static UnsafeAllocator create() {
- return new UnsafeAllocator() {
- @Override
- @SuppressWarnings("unchecked")
- public <T> T newInstance(Class<T> c) throws Exception {
- Unsafe unsafe = sun.misc.Unsafe.theUnsafe; // <--
- return (T) unsafe.allocateInstance(c); // <--
- }
- };
- }
- }
那么final字段是怎么處理的?
答案是,通過反射。詳細(xì)情況可以參考這個(gè)問題,下面我們僅通過代碼來證明這一點(diǎn):
- class MyObj {
-
- public final int x;
-
- public MyObj(int x) { // <---
- this.x = x;
- }
-
- }
- @Test
- public void setFinal() throws Exception {
- MyObj obj = new MyObj(1);
- Assert.assertEquals(1, obj.x);
-
- Field f = obj.getClass().getField("x");
- f.setAccessible(true); // <---
- f.set(obj, 2);
- Assert.assertEquals(2, obj.x);
- }
測試通過!
結(jié)論
反序列化時(shí),如果一個(gè)類沒有默認(rèn)構(gòu)造函數(shù),那么GSON是通過JDK內(nèi)部API來創(chuàng)建對象實(shí)例的,并且通過反射給final字段賦值。
這種做法通常是很危險(xiǎn)的,所以非專業(yè)人士請勿效仿!
|