Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 格森元';不能正确序列化扩展HashMap的类_Java_Gson - Fatal编程技术网

Java 格森元';不能正确序列化扩展HashMap的类

Java 格森元';不能正确序列化扩展HashMap的类,java,gson,Java,Gson,我有以下代码: public static class A { public A() {} private List<B> bs = new ArrayList<B>(); public List<B> getBs() { return bs; } public void setBs(List<B> bs) { this.bs = bs; } } public sta

我有以下代码:

public static class A
{
    public A() {}
    private List<B> bs = new ArrayList<B>();
    public List<B> getBs() {
        return bs;
    }
    public void setBs(List<B> bs) {
        this.bs = bs;
    }
}

public static class B
{
    B(String foo){this.foo=foo;}
    private String foo;
    public String getFoo() {
        return foo;
    }
    public void setFoo(String foo) {
        this.foo = foo;
    }
}

public static void main(String[] args) throws Exception {
    Gson gson = new Gson();
    A a = new A();
    a.getBs().add(new B("bar"));
    System.out.println(gson.toJson(a));
}
但是,如果我创建HashMap的子类:

public static class A extends HashMap
我得到一个返回的空集:{}

我甚至试过:

System.out.println(gson.toJson(a, new TypeToken<A>(){}.getType()));
System.out.println(gson.toJson(一个新的TypeToken(){}.getType());
以及:

System.out.println(gson.toJson(一个新的TypeToken(){}.getType());
有人能告诉我是否/如何使用GSON序列化这个HashMap子类吗?

GSON使用(默认和自定义)
TypeAdapterFactory
实例和它们创建的用于序列化/反序列化对象的
TypeAdapter
对象

它遍历已注册的
TypeAdapterFactory
对象列表,并选择第一个可以为您提供的对象类型创建适当的
TypeAdapter
。其中一个
TypeAdapterFactory
对象是类型
MapTypeAdapterFactory
的对象,它创建了一个
TypeAdapter
(类型
MapTypeAdapterFactory$Adapter
),它基于
java.util.Map
接口(键/值)进行序列化/反序列化。它对自定义子类型的字段没有任何作用


如果您希望Gson将您的类型序列化为
映射和自定义类型,则需要直接注册自定义
TypeAdapter
,或注册创建
TypeAdapter
对象的自定义
TypeAdapter工厂。

这是自定义TypeAdapter工厂

测试:

RetainieldMapFactory.java:

/**
 * Created by linfaxin on 2015/4/9 009.
 * Email: linlinfaxin@163.com
 */
public class RetainFieldMapFactory implements TypeAdapterFactory {

    FieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
    ConstructorConstructor constructorConstructor = new ConstructorConstructor(Collections.<Type, InstanceCreator<?>>emptyMap());
    MapTypeAdapterFactory defaultMapFactory = new MapTypeAdapterFactory(constructorConstructor, false);
    ReflectiveFilterMapFieldFactory defaultObjectFactory = new ReflectiveFilterMapFieldFactory(constructorConstructor,
            fieldNamingPolicy, Excluder.DEFAULT);

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> mapAdapter = defaultMapFactory.create(gson, type);
        if(mapAdapter!=null){
            return (TypeAdapter<T>) new RetainFieldMapAdapter(mapAdapter, defaultObjectFactory.create(gson, type));
        }
        return mapAdapter;
    }


    class RetainFieldMapAdapter extends TypeAdapter<Map<String, Object>>{
        TypeAdapter<Map<String, Object>> mapAdapter;
        ReflectiveTypeAdapterFactory.Adapter<Map<String, Object>> objectAdapter;
        RetainFieldMapAdapter(TypeAdapter mapAdapter, ReflectiveTypeAdapterFactory.Adapter objectAdapter) {
            this.mapAdapter = mapAdapter;
            this.objectAdapter = objectAdapter;
        }

        @Override
        public void write(final JsonWriter out, Map<String, Object> value) throws IOException {
            //1.write object
            StringWriter sw = new StringWriter();
            objectAdapter.write(new JsonWriter(sw), value);

            //2.convert object to a map
            Map<String, Object> objectMap = mapAdapter.fromJson(sw.toString());

            //3.overwrite fields in object to a copy map
            value = new LinkedHashMap<String, Object>(value);
            value.putAll(objectMap);

            //4.write the copy map
            mapAdapter.write(out, value);
        }

        @Override
        public Map<String, Object> read(JsonReader in) throws IOException {
            //1.create map, all key-value retain in map
            Map<String, Object> map = mapAdapter.read(in);

            //2.create object from created map
            Map<String, Object> object = objectAdapter.fromJsonTree(mapAdapter.toJsonTree(map));

            //3.remove fields in object from map
            for(String field : objectAdapter.boundFields.keySet()){
                map.remove(field);
            }
            //4.put map to object
            object.putAll(map);
            return object;
        }
    }

    /**
     * If class is extends from some custom map,
     * class should implement this to avoid serialize custom map's fields
     */
    public interface RetainFieldFlag {}

    static class ReflectiveFilterMapFieldFactory extends ReflectiveTypeAdapterFactory{
        public ReflectiveFilterMapFieldFactory(ConstructorConstructor constructorConstructor, FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {
            super(constructorConstructor, fieldNamingPolicy, excluder);
        }

        @Override
        protected boolean shouldFindFieldInClass(Class willFindClass, Class<?> originalRaw) {
            if(RetainFieldFlag.class.isAssignableFrom(originalRaw)){
                return RetainFieldFlag.class.isAssignableFrom(willFindClass);
            }else{
                Class[] endClasses = new Class[]{Object.class, HashMap.class, LinkedHashMap.class,
                        LinkedTreeMap.class, Hashtable.class, TreeMap.class, ConcurrentHashMap.class,
                        IdentityHashMap.class, WeakHashMap.class, EnumMap.class};
                for(Class c : endClasses){
                    if(willFindClass == c) return false;
                }
            }
            return super.shouldFindFieldInClass(willFindClass, originalRaw);
        }
    }
    /**
     * below code copy from {@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory}
     * (little modify, in source this class is final)
     * Type adapter that reflects over the fields and methods of a class.
     */
    static class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
        private final ConstructorConstructor constructorConstructor;
        private final FieldNamingStrategy fieldNamingPolicy;
        private final Excluder excluder;

        public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,
                                            FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {
            this.constructorConstructor = constructorConstructor;
            this.fieldNamingPolicy = fieldNamingPolicy;
            this.excluder = excluder;
        }

        public boolean excludeField(Field f, boolean serialize) {
            return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);
        }

        private String getFieldName(Field f) {
            SerializedName serializedName = f.getAnnotation(SerializedName.class);
            return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();
        }

        public <T> Adapter<T> create(Gson gson, final TypeToken<T> type) {
            Class<? super T> raw = type.getRawType();

            if (!Object.class.isAssignableFrom(raw)) {
                return null; // it's a primitive!
            }

            ObjectConstructor<T> constructor = constructorConstructor.get(type);
            return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
        }

        private ReflectiveTypeAdapterFactory.BoundField createBoundField(
                final Gson context, final Field field, final String name,
                final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
            final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());

            // special casing primitives here saves ~5% on Android...
            return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
                final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
                @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
                @Override void write(JsonWriter writer, Object value)
                        throws IOException, IllegalAccessException {
                    Object fieldValue = field.get(value);
                    TypeAdapter t = new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());
                    t.write(writer, fieldValue);
                }
                @Override void read(JsonReader reader, Object value)
                        throws IOException, IllegalAccessException {
                    Object fieldValue = typeAdapter.read(reader);
                    if (fieldValue != null || !isPrimitive) {
                        field.set(value, fieldValue);
                    }
                }
            };
        }

        private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
            Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
            if (raw.isInterface()) {
                return result;
            }

            Type declaredType = type.getType();
            Class<?> originalRaw = type.getRawType();
            while (shouldFindFieldInClass(raw, originalRaw)) {
                Field[] fields = raw.getDeclaredFields();
                for (Field field : fields) {
                    boolean serialize = excludeField(field, true);
                    boolean deserialize = excludeField(field, false);
                    if (!serialize && !deserialize) {
                        continue;
                    }
                    field.setAccessible(true);
                    Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
                    BoundField boundField = createBoundField(context, field, getFieldName(field),
                            TypeToken.get(fieldType), serialize, deserialize);
                    BoundField previous = result.put(boundField.name, boundField);
                    if (previous != null) {
                        throw new IllegalArgumentException(declaredType
                                + " declares multiple JSON fields named " + previous.name);
                    }
                }
                type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
                raw = type.getRawType();
            }
            return result;
        }
        protected boolean shouldFindFieldInClass(Class willFindClass, Class<?> originalRaw){
            return willFindClass != Object.class;
        }

        static abstract class BoundField {
            final String name;
            final boolean serialized;
            final boolean deserialized;

            protected BoundField(String name, boolean serialized, boolean deserialized) {
                this.name = name;
                this.serialized = serialized;
                this.deserialized = deserialized;
            }

            abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
            abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
        }

        public static final class Adapter<T> extends TypeAdapter<T> {
            private final ObjectConstructor<T> constructor;
            private final Map<String, BoundField> boundFields;

            private Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
                this.constructor = constructor;
                this.boundFields = boundFields;
            }

            @Override public T read(JsonReader in) throws IOException {
                if (in.peek() == JsonToken.NULL) {
                    in.nextNull();
                    return null;
                }

                T instance = constructor.construct();

                try {
                    in.beginObject();
                    while (in.hasNext()) {
                        String name = in.nextName();
                        BoundField field = boundFields.get(name);
                        if (field == null || !field.deserialized) {
                            in.skipValue();
                        } else {
                            field.read(in, instance);
                        }
                    }
                } catch (IllegalStateException e) {
                    throw new JsonSyntaxException(e);
                } catch (IllegalAccessException e) {
                    throw new AssertionError(e);
                }
                in.endObject();
                return instance;
            }

            @Override public void write(JsonWriter out, T value) throws IOException {
                if (value == null) {
                    out.nullValue();
                    return;
                }

                out.beginObject();
                try {
                    for (BoundField boundField : boundFields.values()) {
                        if (boundField.serialized) {
                            out.name(boundField.name);
                            boundField.write(out, value);
                        }
                    }
                } catch (IllegalAccessException e) {
                    throw new AssertionError();
                }
                out.endObject();
            }
        }
    }


    static class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
        private final Gson context;
        private final TypeAdapter<T> delegate;
        private final Type type;

        TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {
            this.context = context;
            this.delegate = delegate;
            this.type = type;
        }

        @Override
        public T read(JsonReader in) throws IOException {
            return delegate.read(in);
        }

        @SuppressWarnings({"rawtypes", "unchecked"})
        @Override
        public void write(JsonWriter out, T value) throws IOException {
            // Order of preference for choosing type adapters
            // First preference: a type adapter registered for the runtime type
            // Second preference: a type adapter registered for the declared type
            // Third preference: reflective type adapter for the runtime type (if it is a sub class of the declared type)
            // Fourth preference: reflective type adapter for the declared type

            TypeAdapter chosen = delegate;
            Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);
            if (runtimeType != type) {
                TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));
                if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
                    // The user registered a type adapter for the runtime type, so we will use that
                    chosen = runtimeTypeAdapter;
                } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {
                    // The user registered a type adapter for Base class, so we prefer it over the
                    // reflective type adapter for the runtime type
                    chosen = delegate;
                } else {
                    // Use the type adapter for runtime type
                    chosen = runtimeTypeAdapter;
                }
            }
            chosen.write(out, value);
        }

        /**
         * Finds a compatible runtime type if it is more specific
         */
        private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
            if (value != null
                    && (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
                type = value.getClass();
            }
            return type;
        }
    }

}
/**
*由linfaxin于2015/4/9 009创建。
*电邮:linlinfaxin@163.com
*/
公共类RetainFieldMapFactory实现TypeAdapterFactory{
FieldNamingPolicy FieldNamingPolicy=FieldNamingPolicy.IDENTITY;
ConstructorConstructor ConstructorConstructor=新的ConstructorConstructor(Collections.fieldType、布尔序列化、布尔反序列化){
final boolean isPrimitive=Primitives.isPrimitive(fieldType.getRawType());
//这里的特殊外壳原语在Android上节省约5%。。。
返回新的ReflectTypeAdapterFactory.BoundField(名称、序列化、反序列化){
final-TypeAdapter-TypeAdapter=context.getAdapter(fieldType);
@SuppressWarnings({“unchecked”,“rawtypes”})//类型适配器和字段类型始终一致
@重写无效写入(JsonWriter写入程序,对象值)
抛出IOException,IllegalAccessException{
对象fieldValue=field.get(值);
TypeAdapter t=新的TypeAdapterRuntimeTypeWrapper(上下文,this.TypeAdapter,fieldType.getType());
t、 write(writer,fieldValue);
}
@重写无效读取(JsonReader,对象值)
抛出IOException,IllegalAccessException{
Object fieldValue=typeAdapter.read(读卡器);
if(fieldValue!=null | |!isPrimitive){
field.set(值,fieldValue);
}
}
};
}
私有映射getBoundFields(Gson上下文、TypeToken类型、类原始){
映射结果=新建LinkedHashMap();
if(raw.isInterface()){
返回结果;
}
类型declaredType=Type.getType();
类originalRaw=type.getRawType();
while(应查找字段包括类(原始、原始)){
Field[]fields=raw.getDeclaredFields();
用于(字段:字段){
boolean serialize=excludeField(字段,true);
布尔反序列化=excludeField(字段,false);
如果(!序列化&&!反序列化){
继续;
}
字段。setAccessible(true);
Type fieldType=$Gson$Types.resolve(Type.getType(),raw,field.getGenericType());
BoundField BoundField=CreateBundField(上下文、字段、getFieldName(字段),
获取(fieldType)、序列化、反序列化);
BoundField previous=结果.put(BoundField.name,BoundField);
如果(上一个!=null){
抛出新的IllegalArgumentException(declaredType
+声明多个名为“+previous.name”的JSON字段;
}
}
type=TypeToken.get($Gson$Types.resolve(type.getType(),raw,raw.getGenericSuperclass());
raw=type.getRawType();
}
返回结果;
}
受保护的布尔值shouldFindFieldInClass(类willFindClass,类originalRaw){
返回willFindClass!=Object.class;
}
静态抽象类边界域{
最后的字符串名;
最终布尔序列化;
最终布尔反序列化;
受保护的边界字段(字符串名称、布尔序列化、布尔反序列化){
this.name=名称;
this.serialized=已序列化;
this.deserialized=反序列化;
}
抽象void write(JsonWriter writer,Object value)抛出IOException、IllegalAccessException;
抽象void read(JsonReader,Object value)抛出IOException、IllegalAccessException;
}
公共静态最终类适配器扩展了TypeAdapter{
私有最终对象构造函数;
私有最终地图边界字段;
专用适配器(对象构造函数、映射边界字段){
this.constructor=构造函数;
this.boundFields=boundFields;
}
@重写公共T读(JsonReader in)引发IOException{
if(in.peek()==JsonToken.NULL){
in.nextNull();
System.out.println(gson.toJson(a, new TypeToken<HashMap>(){}.getType()));
public static void main(String[] args) throws Exception{
    Gson gson = new GsonBuilder()
            .registerTypeAdapterFactory(new RetainFieldMapFactory())
            .create();

    Foo f = gson.fromJson("{'key1':'value1','key2':'value2'}", Foo.class);

    System.out.println("in map:\t" + f.toString());
    System.out.println("f.key1:\t"+f.key1);
    System.out.println("toJson:\t"+gson.toJson(f));
}

public static class Foo extends HashMap<String, String> {
    private String key1;
}
in map: {key2=value2}
f.key1: value1
toJson: {"key2":"value2","key1":"value1"}
/**
 * Created by linfaxin on 2015/4/9 009.
 * Email: linlinfaxin@163.com
 */
public class RetainFieldMapFactory implements TypeAdapterFactory {

    FieldNamingPolicy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
    ConstructorConstructor constructorConstructor = new ConstructorConstructor(Collections.<Type, InstanceCreator<?>>emptyMap());
    MapTypeAdapterFactory defaultMapFactory = new MapTypeAdapterFactory(constructorConstructor, false);
    ReflectiveFilterMapFieldFactory defaultObjectFactory = new ReflectiveFilterMapFieldFactory(constructorConstructor,
            fieldNamingPolicy, Excluder.DEFAULT);

    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        final TypeAdapter<T> mapAdapter = defaultMapFactory.create(gson, type);
        if(mapAdapter!=null){
            return (TypeAdapter<T>) new RetainFieldMapAdapter(mapAdapter, defaultObjectFactory.create(gson, type));
        }
        return mapAdapter;
    }


    class RetainFieldMapAdapter extends TypeAdapter<Map<String, Object>>{
        TypeAdapter<Map<String, Object>> mapAdapter;
        ReflectiveTypeAdapterFactory.Adapter<Map<String, Object>> objectAdapter;
        RetainFieldMapAdapter(TypeAdapter mapAdapter, ReflectiveTypeAdapterFactory.Adapter objectAdapter) {
            this.mapAdapter = mapAdapter;
            this.objectAdapter = objectAdapter;
        }

        @Override
        public void write(final JsonWriter out, Map<String, Object> value) throws IOException {
            //1.write object
            StringWriter sw = new StringWriter();
            objectAdapter.write(new JsonWriter(sw), value);

            //2.convert object to a map
            Map<String, Object> objectMap = mapAdapter.fromJson(sw.toString());

            //3.overwrite fields in object to a copy map
            value = new LinkedHashMap<String, Object>(value);
            value.putAll(objectMap);

            //4.write the copy map
            mapAdapter.write(out, value);
        }

        @Override
        public Map<String, Object> read(JsonReader in) throws IOException {
            //1.create map, all key-value retain in map
            Map<String, Object> map = mapAdapter.read(in);

            //2.create object from created map
            Map<String, Object> object = objectAdapter.fromJsonTree(mapAdapter.toJsonTree(map));

            //3.remove fields in object from map
            for(String field : objectAdapter.boundFields.keySet()){
                map.remove(field);
            }
            //4.put map to object
            object.putAll(map);
            return object;
        }
    }

    /**
     * If class is extends from some custom map,
     * class should implement this to avoid serialize custom map's fields
     */
    public interface RetainFieldFlag {}

    static class ReflectiveFilterMapFieldFactory extends ReflectiveTypeAdapterFactory{
        public ReflectiveFilterMapFieldFactory(ConstructorConstructor constructorConstructor, FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {
            super(constructorConstructor, fieldNamingPolicy, excluder);
        }

        @Override
        protected boolean shouldFindFieldInClass(Class willFindClass, Class<?> originalRaw) {
            if(RetainFieldFlag.class.isAssignableFrom(originalRaw)){
                return RetainFieldFlag.class.isAssignableFrom(willFindClass);
            }else{
                Class[] endClasses = new Class[]{Object.class, HashMap.class, LinkedHashMap.class,
                        LinkedTreeMap.class, Hashtable.class, TreeMap.class, ConcurrentHashMap.class,
                        IdentityHashMap.class, WeakHashMap.class, EnumMap.class};
                for(Class c : endClasses){
                    if(willFindClass == c) return false;
                }
            }
            return super.shouldFindFieldInClass(willFindClass, originalRaw);
        }
    }
    /**
     * below code copy from {@link com.google.gson.internal.bind.ReflectiveTypeAdapterFactory}
     * (little modify, in source this class is final)
     * Type adapter that reflects over the fields and methods of a class.
     */
    static class ReflectiveTypeAdapterFactory implements TypeAdapterFactory {
        private final ConstructorConstructor constructorConstructor;
        private final FieldNamingStrategy fieldNamingPolicy;
        private final Excluder excluder;

        public ReflectiveTypeAdapterFactory(ConstructorConstructor constructorConstructor,
                                            FieldNamingStrategy fieldNamingPolicy, Excluder excluder) {
            this.constructorConstructor = constructorConstructor;
            this.fieldNamingPolicy = fieldNamingPolicy;
            this.excluder = excluder;
        }

        public boolean excludeField(Field f, boolean serialize) {
            return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);
        }

        private String getFieldName(Field f) {
            SerializedName serializedName = f.getAnnotation(SerializedName.class);
            return serializedName == null ? fieldNamingPolicy.translateName(f) : serializedName.value();
        }

        public <T> Adapter<T> create(Gson gson, final TypeToken<T> type) {
            Class<? super T> raw = type.getRawType();

            if (!Object.class.isAssignableFrom(raw)) {
                return null; // it's a primitive!
            }

            ObjectConstructor<T> constructor = constructorConstructor.get(type);
            return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
        }

        private ReflectiveTypeAdapterFactory.BoundField createBoundField(
                final Gson context, final Field field, final String name,
                final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
            final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());

            // special casing primitives here saves ~5% on Android...
            return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
                final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
                @SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
                @Override void write(JsonWriter writer, Object value)
                        throws IOException, IllegalAccessException {
                    Object fieldValue = field.get(value);
                    TypeAdapter t = new TypeAdapterRuntimeTypeWrapper(context, this.typeAdapter, fieldType.getType());
                    t.write(writer, fieldValue);
                }
                @Override void read(JsonReader reader, Object value)
                        throws IOException, IllegalAccessException {
                    Object fieldValue = typeAdapter.read(reader);
                    if (fieldValue != null || !isPrimitive) {
                        field.set(value, fieldValue);
                    }
                }
            };
        }

        private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
            Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
            if (raw.isInterface()) {
                return result;
            }

            Type declaredType = type.getType();
            Class<?> originalRaw = type.getRawType();
            while (shouldFindFieldInClass(raw, originalRaw)) {
                Field[] fields = raw.getDeclaredFields();
                for (Field field : fields) {
                    boolean serialize = excludeField(field, true);
                    boolean deserialize = excludeField(field, false);
                    if (!serialize && !deserialize) {
                        continue;
                    }
                    field.setAccessible(true);
                    Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
                    BoundField boundField = createBoundField(context, field, getFieldName(field),
                            TypeToken.get(fieldType), serialize, deserialize);
                    BoundField previous = result.put(boundField.name, boundField);
                    if (previous != null) {
                        throw new IllegalArgumentException(declaredType
                                + " declares multiple JSON fields named " + previous.name);
                    }
                }
                type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
                raw = type.getRawType();
            }
            return result;
        }
        protected boolean shouldFindFieldInClass(Class willFindClass, Class<?> originalRaw){
            return willFindClass != Object.class;
        }

        static abstract class BoundField {
            final String name;
            final boolean serialized;
            final boolean deserialized;

            protected BoundField(String name, boolean serialized, boolean deserialized) {
                this.name = name;
                this.serialized = serialized;
                this.deserialized = deserialized;
            }

            abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
            abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
        }

        public static final class Adapter<T> extends TypeAdapter<T> {
            private final ObjectConstructor<T> constructor;
            private final Map<String, BoundField> boundFields;

            private Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
                this.constructor = constructor;
                this.boundFields = boundFields;
            }

            @Override public T read(JsonReader in) throws IOException {
                if (in.peek() == JsonToken.NULL) {
                    in.nextNull();
                    return null;
                }

                T instance = constructor.construct();

                try {
                    in.beginObject();
                    while (in.hasNext()) {
                        String name = in.nextName();
                        BoundField field = boundFields.get(name);
                        if (field == null || !field.deserialized) {
                            in.skipValue();
                        } else {
                            field.read(in, instance);
                        }
                    }
                } catch (IllegalStateException e) {
                    throw new JsonSyntaxException(e);
                } catch (IllegalAccessException e) {
                    throw new AssertionError(e);
                }
                in.endObject();
                return instance;
            }

            @Override public void write(JsonWriter out, T value) throws IOException {
                if (value == null) {
                    out.nullValue();
                    return;
                }

                out.beginObject();
                try {
                    for (BoundField boundField : boundFields.values()) {
                        if (boundField.serialized) {
                            out.name(boundField.name);
                            boundField.write(out, value);
                        }
                    }
                } catch (IllegalAccessException e) {
                    throw new AssertionError();
                }
                out.endObject();
            }
        }
    }


    static class TypeAdapterRuntimeTypeWrapper<T> extends TypeAdapter<T> {
        private final Gson context;
        private final TypeAdapter<T> delegate;
        private final Type type;

        TypeAdapterRuntimeTypeWrapper(Gson context, TypeAdapter<T> delegate, Type type) {
            this.context = context;
            this.delegate = delegate;
            this.type = type;
        }

        @Override
        public T read(JsonReader in) throws IOException {
            return delegate.read(in);
        }

        @SuppressWarnings({"rawtypes", "unchecked"})
        @Override
        public void write(JsonWriter out, T value) throws IOException {
            // Order of preference for choosing type adapters
            // First preference: a type adapter registered for the runtime type
            // Second preference: a type adapter registered for the declared type
            // Third preference: reflective type adapter for the runtime type (if it is a sub class of the declared type)
            // Fourth preference: reflective type adapter for the declared type

            TypeAdapter chosen = delegate;
            Type runtimeType = getRuntimeTypeIfMoreSpecific(type, value);
            if (runtimeType != type) {
                TypeAdapter runtimeTypeAdapter = context.getAdapter(TypeToken.get(runtimeType));
                if (!(runtimeTypeAdapter instanceof ReflectiveTypeAdapterFactory.Adapter)) {
                    // The user registered a type adapter for the runtime type, so we will use that
                    chosen = runtimeTypeAdapter;
                } else if (!(delegate instanceof ReflectiveTypeAdapterFactory.Adapter)) {
                    // The user registered a type adapter for Base class, so we prefer it over the
                    // reflective type adapter for the runtime type
                    chosen = delegate;
                } else {
                    // Use the type adapter for runtime type
                    chosen = runtimeTypeAdapter;
                }
            }
            chosen.write(out, value);
        }

        /**
         * Finds a compatible runtime type if it is more specific
         */
        private Type getRuntimeTypeIfMoreSpecific(Type type, Object value) {
            if (value != null
                    && (type == Object.class || type instanceof TypeVariable<?> || type instanceof Class<?>)) {
                type = value.getClass();
            }
            return type;
        }
    }

}