Added support for deserialization exclusion strategy.
This commit is contained in:
parent
3331dcdab0
commit
f276d13827
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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<E> extends TypeAdapter<Object> {
|
||||
public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
@ -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<E> extends TypeAdapter<Collection<E>> {
|
||||
public final class CollectionTypeAdapter<E> extends TypeAdapter<Collection<E>> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
@ -50,16 +50,20 @@ public final class MiniGson {
|
||||
|
||||
private MiniGson(Builder builder) {
|
||||
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.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);
|
||||
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<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||
boolean addDefaultFactories = true;
|
||||
|
||||
public Builder factory(TypeAdapter.Factory factory) {
|
||||
factories.add(factory);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withoutDefaultFactories() {
|
||||
this.addDefaultFactories = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> Builder typeAdapter(final Class<T> type, final TypeAdapter<T> typeAdapter) {
|
||||
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
||||
return this;
|
||||
|
@ -60,7 +60,7 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
||||
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,9 +83,11 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
||||
writer.beginObject();
|
||||
try {
|
||||
for (BoundField boundField : boundFields) {
|
||||
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<T> extends TypeAdapter<T> {
|
||||
}
|
||||
|
||||
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<T> extends TypeAdapter<T> {
|
||||
}
|
||||
|
||||
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 <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||
Class<? super T> raw = type.getRawType();
|
||||
@ -139,14 +144,15 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
||||
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));
|
||||
BoundField boundField = createBoundField(context, field, TypeToken.get(fieldType), serialize, deserialize);
|
||||
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<T> extends TypeAdapter<T> {
|
||||
|
||||
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;
|
||||
|
@ -31,7 +31,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Adapt a map whose keys are strings.
|
||||
*/
|
||||
final class StringToValueMapTypeAdapter<V> extends TypeAdapter<Map<String, V>> {
|
||||
public final class StringToValueMapTypeAdapter<V> extends TypeAdapter<Map<String, V>> {
|
||||
public static final Factory FACTORY = new Factory() {
|
||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
|
@ -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> BOOLEAN = new TypeAdapter<Boolean>() {
|
||||
|
Loading…
Reference in New Issue
Block a user