From f276d1382775e962d1a0a4b9e7e3e08496252861 Mon Sep 17 00:00:00 2001 From: Inderjeet Singh Date: Wed, 3 Aug 2011 01:19:26 +0000 Subject: [PATCH] Added support for deserialization exclusion strategy. --- gson/src/main/java/com/google/gson/Gson.java | 28 +++++++++++--- .../gson/internal/bind/ArrayTypeAdapter.java | 13 ++++--- .../internal/bind/CollectionTypeAdapter.java | 13 ++++--- .../google/gson/internal/bind/MiniGson.java | 28 +++++++++----- .../internal/bind/ReflectiveTypeAdapter.java | 38 ++++++++++++------- .../bind/StringToValueMapTypeAdapter.java | 2 +- .../gson/internal/bind/TypeAdapters.java | 2 +- 7 files changed, 82 insertions(+), 42 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 9e411b41..23d84623 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -28,9 +28,13 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import com.google.gson.internal.bind.ArrayTypeAdapter; +import com.google.gson.internal.bind.CollectionTypeAdapter; import com.google.gson.internal.bind.MiniGson; import com.google.gson.internal.bind.ReflectiveTypeAdapter; +import com.google.gson.internal.bind.StringToValueMapTypeAdapter; import com.google.gson.internal.bind.TypeAdapter; +import com.google.gson.internal.bind.TypeAdapters; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; @@ -183,17 +187,31 @@ public final class Gson { serializeNulls serializers */ - TypeAdapter.Factory factory = new ReflectiveTypeAdapter.FactoryImpl() { + TypeAdapter.Factory reflectiveTypeAdapterFactory = + new ReflectiveTypeAdapter.FactoryImpl() { @Override - public boolean skipField(Class declaringClazz, Field f, Type declaredType) { - // TODO: support deserialization policy as well - return Gson.this.serializationExclusionStrategy.shouldSkipField( + public boolean serializeField(Class declaringClazz, Field f, Type declaredType) { + return !Gson.this.serializationExclusionStrategy.shouldSkipField( + new FieldAttributes(declaringClazz, f, declaredType)); + } + @Override + public boolean deserializeField(Class declaringClazz, Field f, Type declaredType) { + return !Gson.this.deserializationExclusionStrategy.shouldSkipField( new FieldAttributes(declaringClazz, f, declaredType)); } }; this.miniGson = new MiniGson.Builder() - .factory(factory) + .withoutDefaultFactories() + .factory(TypeAdapters.BOOLEAN_FACTORY) + .factory(TypeAdapters.INTEGER_FACTORY) + .factory(TypeAdapters.DOUBLE_FACTORY) + .factory(TypeAdapters.LONG_FACTORY) + .factory(TypeAdapters.STRING_FACTORY) + .factory(CollectionTypeAdapter.FACTORY) + .factory(StringToValueMapTypeAdapter.FACTORY) + .factory(ArrayTypeAdapter.FACTORY) + .factory(reflectiveTypeAdapterFactory) .build(); } diff --git a/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java index 2376d948..da7cc5dd 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/ArrayTypeAdapter.java @@ -16,11 +16,6 @@ package com.google.gson.internal.bind; -import com.google.gson.internal.$Gson$Types; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; @@ -28,10 +23,16 @@ import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; +import com.google.gson.internal.$Gson$Types; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + /** * Adapt an array of objects. */ -final class ArrayTypeAdapter extends TypeAdapter { +public final class ArrayTypeAdapter extends TypeAdapter { public static final Factory FACTORY = new Factory() { public TypeAdapter create(MiniGson context, TypeToken typeToken) { Type type = typeToken.getType(); diff --git a/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java index a7c43cf7..fa63a3be 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/CollectionTypeAdapter.java @@ -16,11 +16,6 @@ package com.google.gson.internal.bind; -import com.google.gson.internal.$Gson$Types; -import com.google.gson.reflect.TypeToken; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonToken; -import com.google.gson.stream.JsonWriter; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.ParameterizedType; @@ -31,10 +26,16 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; +import com.google.gson.internal.$Gson$Types; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + /** * Adapt a homogeneous collection of objects. */ -final class CollectionTypeAdapter extends TypeAdapter> { +public final class CollectionTypeAdapter extends TypeAdapter> { public static final Factory FACTORY = new Factory() { public TypeAdapter create(MiniGson context, TypeToken typeToken) { Type type = typeToken.getType(); diff --git a/gson/src/main/java/com/google/gson/internal/bind/MiniGson.java b/gson/src/main/java/com/google/gson/internal/bind/MiniGson.java index 69b48b5c..97cd38b1 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/MiniGson.java +++ b/gson/src/main/java/com/google/gson/internal/bind/MiniGson.java @@ -50,16 +50,20 @@ public final class MiniGson { private MiniGson(Builder builder) { List factories = new ArrayList(); - factories.add(TypeAdapters.BOOLEAN_FACTORY); - factories.add(TypeAdapters.INTEGER_FACTORY); - factories.add(TypeAdapters.DOUBLE_FACTORY); - factories.add(TypeAdapters.LONG_FACTORY); - factories.add(TypeAdapters.STRING_FACTORY); + if (builder.addDefaultFactories) { + factories.add(TypeAdapters.BOOLEAN_FACTORY); + factories.add(TypeAdapters.INTEGER_FACTORY); + factories.add(TypeAdapters.DOUBLE_FACTORY); + factories.add(TypeAdapters.LONG_FACTORY); + factories.add(TypeAdapters.STRING_FACTORY); + } factories.addAll(builder.factories); - factories.add(CollectionTypeAdapter.FACTORY); - factories.add(StringToValueMapTypeAdapter.FACTORY); - factories.add(ArrayTypeAdapter.FACTORY); - factories.add(ReflectiveTypeAdapter.FACTORY); + if (builder.addDefaultFactories) { + factories.add(CollectionTypeAdapter.FACTORY); + factories.add(StringToValueMapTypeAdapter.FACTORY); + factories.add(ArrayTypeAdapter.FACTORY); + factories.add(ReflectiveTypeAdapter.FACTORY); + } this.factories = Collections.unmodifiableList(factories); } @@ -156,12 +160,18 @@ public final class MiniGson { public static final class Builder { private final List factories = new ArrayList(); + boolean addDefaultFactories = true; public Builder factory(TypeAdapter.Factory factory) { factories.add(factory); return this; } + public Builder withoutDefaultFactories() { + this.addDefaultFactories = false; + return this; + } + public Builder typeAdapter(final Class type, final TypeAdapter typeAdapter) { factories.add(TypeAdapters.newFactory(type, typeAdapter)); return this; diff --git a/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapter.java index e4907b4c..a3efca06 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/ReflectiveTypeAdapter.java @@ -60,7 +60,7 @@ public final class ReflectiveTypeAdapter extends TypeAdapter { while (reader.hasNext()) { String name = reader.nextName(); BoundField field = map.get(name); - if (field == null) { + if (field == null || !field.deserialized) { // TODO: define a better policy reader.skipValue(); } else { @@ -83,8 +83,10 @@ public final class ReflectiveTypeAdapter extends TypeAdapter { writer.beginObject(); try { for (BoundField boundField : boundFields) { - writer.name(boundField.name); - boundField.write(writer, value); + if (boundField.serialized) { + writer.name(boundField.name); + boundField.write(writer, value); + } } } catch (IllegalAccessException e) { throw new AssertionError(); @@ -93,9 +95,9 @@ public final class ReflectiveTypeAdapter extends TypeAdapter { } static BoundField createBoundField( - final MiniGson context, final Field field, final TypeToken fieldType) { + final MiniGson context, final Field field, final TypeToken fieldType, boolean serialize, boolean deserialize) { // special casing primitives here saves ~5% on Android... - return new BoundField(field.getName()) { + return new BoundField(field.getName(), serialize, deserialize) { final TypeAdapter typeAdapter = context.getAdapter(fieldType); @SuppressWarnings("unchecked") // the type adapter and field type always agree @Override void write(JsonWriter writer, Object value) @@ -112,8 +114,11 @@ public final class ReflectiveTypeAdapter extends TypeAdapter { } public static class FactoryImpl implements Factory { - public boolean skipField(Class declaringClazz, Field f, Type declaringType) { - return false; + public boolean serializeField(Class declaringClazz, Field f, Type declaringType) { + return true; + } + public boolean deserializeField(Class declaringClazz, Field f, Type declaringType) { + return true; } public TypeAdapter create(MiniGson context, TypeToken type) { Class raw = type.getRawType(); @@ -139,13 +144,14 @@ public final class ReflectiveTypeAdapter extends TypeAdapter { Type declaredType = type.getType(); while (raw != Object.class) { for (Field field : raw.getDeclaredFields()) { - if (skipField(raw, field, declaredType)) { - continue; + boolean serialize = serializeField(raw, field, declaredType); + boolean deserialize = deserializeField(raw, field, declaredType); + if (serialize || deserialize) { + field.setAccessible(true); // TODO: don't call setAccessible unless necessary + Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); + BoundField boundField = createBoundField(context, field, TypeToken.get(fieldType), serialize, deserialize); + result.put(boundField.name, boundField); } - field.setAccessible(true); // TODO: don't call setAccessible unless necessary - Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType()); - BoundField boundField = createBoundField(context, field, TypeToken.get(fieldType)); - result.put(boundField.name, boundField); } type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass())); raw = type.getRawType(); @@ -156,9 +162,13 @@ public final class ReflectiveTypeAdapter extends TypeAdapter { static abstract class BoundField { final String name; + final boolean serialized; + final boolean deserialized; - protected BoundField(String name) { + 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; diff --git a/gson/src/main/java/com/google/gson/internal/bind/StringToValueMapTypeAdapter.java b/gson/src/main/java/com/google/gson/internal/bind/StringToValueMapTypeAdapter.java index 3a3d6f6a..7fc2063f 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/StringToValueMapTypeAdapter.java +++ b/gson/src/main/java/com/google/gson/internal/bind/StringToValueMapTypeAdapter.java @@ -31,7 +31,7 @@ import java.util.Map; /** * Adapt a map whose keys are strings. */ -final class StringToValueMapTypeAdapter extends TypeAdapter> { +public final class StringToValueMapTypeAdapter extends TypeAdapter> { public static final Factory FACTORY = new Factory() { public TypeAdapter create(MiniGson context, TypeToken typeToken) { Type type = typeToken.getType(); diff --git a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java index 4bfd71cc..563a09e9 100644 --- a/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java +++ b/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java @@ -24,7 +24,7 @@ import java.io.IOException; /** * Type adapters for basic types. */ -final class TypeAdapters { +public final class TypeAdapters { private TypeAdapters() {} public static final TypeAdapter BOOLEAN = new TypeAdapter() {