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.List;
|
||||||
import java.util.Map;
|
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.MiniGson;
|
||||||
import com.google.gson.internal.bind.ReflectiveTypeAdapter;
|
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.TypeAdapter;
|
||||||
|
import com.google.gson.internal.bind.TypeAdapters;
|
||||||
import com.google.gson.reflect.TypeToken;
|
import com.google.gson.reflect.TypeToken;
|
||||||
import com.google.gson.stream.JsonReader;
|
import com.google.gson.stream.JsonReader;
|
||||||
import com.google.gson.stream.JsonToken;
|
import com.google.gson.stream.JsonToken;
|
||||||
@ -183,17 +187,31 @@ public final class Gson {
|
|||||||
serializeNulls
|
serializeNulls
|
||||||
serializers
|
serializers
|
||||||
*/
|
*/
|
||||||
TypeAdapter.Factory factory = new ReflectiveTypeAdapter.FactoryImpl() {
|
TypeAdapter.Factory reflectiveTypeAdapterFactory =
|
||||||
|
new ReflectiveTypeAdapter.FactoryImpl() {
|
||||||
@Override
|
@Override
|
||||||
public boolean skipField(Class<?> declaringClazz, Field f, Type declaredType) {
|
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) {
|
||||||
// TODO: support deserialization policy as well
|
return !Gson.this.serializationExclusionStrategy.shouldSkipField(
|
||||||
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));
|
new FieldAttributes(declaringClazz, f, declaredType));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.miniGson = new MiniGson.Builder()
|
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();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
package com.google.gson.internal.bind;
|
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.io.IOException;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.GenericArrayType;
|
import java.lang.reflect.GenericArrayType;
|
||||||
@ -28,10 +23,16 @@ import java.lang.reflect.Type;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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.
|
* 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 static final Factory FACTORY = new Factory() {
|
||||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||||
Type type = typeToken.getType();
|
Type type = typeToken.getType();
|
||||||
|
@ -16,11 +16,6 @@
|
|||||||
|
|
||||||
package com.google.gson.internal.bind;
|
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.io.IOException;
|
||||||
import java.lang.reflect.Constructor;
|
import java.lang.reflect.Constructor;
|
||||||
import java.lang.reflect.ParameterizedType;
|
import java.lang.reflect.ParameterizedType;
|
||||||
@ -31,10 +26,16 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
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.
|
* 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 static final Factory FACTORY = new Factory() {
|
||||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||||
Type type = typeToken.getType();
|
Type type = typeToken.getType();
|
||||||
|
@ -50,16 +50,20 @@ public final class MiniGson {
|
|||||||
|
|
||||||
private MiniGson(Builder builder) {
|
private MiniGson(Builder builder) {
|
||||||
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||||
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
if (builder.addDefaultFactories) {
|
||||||
factories.add(TypeAdapters.INTEGER_FACTORY);
|
factories.add(TypeAdapters.BOOLEAN_FACTORY);
|
||||||
factories.add(TypeAdapters.DOUBLE_FACTORY);
|
factories.add(TypeAdapters.INTEGER_FACTORY);
|
||||||
factories.add(TypeAdapters.LONG_FACTORY);
|
factories.add(TypeAdapters.DOUBLE_FACTORY);
|
||||||
factories.add(TypeAdapters.STRING_FACTORY);
|
factories.add(TypeAdapters.LONG_FACTORY);
|
||||||
|
factories.add(TypeAdapters.STRING_FACTORY);
|
||||||
|
}
|
||||||
factories.addAll(builder.factories);
|
factories.addAll(builder.factories);
|
||||||
factories.add(CollectionTypeAdapter.FACTORY);
|
if (builder.addDefaultFactories) {
|
||||||
factories.add(StringToValueMapTypeAdapter.FACTORY);
|
factories.add(CollectionTypeAdapter.FACTORY);
|
||||||
factories.add(ArrayTypeAdapter.FACTORY);
|
factories.add(StringToValueMapTypeAdapter.FACTORY);
|
||||||
factories.add(ReflectiveTypeAdapter.FACTORY);
|
factories.add(ArrayTypeAdapter.FACTORY);
|
||||||
|
factories.add(ReflectiveTypeAdapter.FACTORY);
|
||||||
|
}
|
||||||
this.factories = Collections.unmodifiableList(factories);
|
this.factories = Collections.unmodifiableList(factories);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,12 +160,18 @@ public final class MiniGson {
|
|||||||
|
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
private final List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
private final List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
|
||||||
|
boolean addDefaultFactories = true;
|
||||||
|
|
||||||
public Builder factory(TypeAdapter.Factory factory) {
|
public Builder factory(TypeAdapter.Factory factory) {
|
||||||
factories.add(factory);
|
factories.add(factory);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Builder withoutDefaultFactories() {
|
||||||
|
this.addDefaultFactories = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public <T> Builder typeAdapter(final Class<T> type, final TypeAdapter<T> typeAdapter) {
|
public <T> Builder typeAdapter(final Class<T> type, final TypeAdapter<T> typeAdapter) {
|
||||||
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
factories.add(TypeAdapters.newFactory(type, typeAdapter));
|
||||||
return this;
|
return this;
|
||||||
|
@ -60,7 +60,7 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
|||||||
while (reader.hasNext()) {
|
while (reader.hasNext()) {
|
||||||
String name = reader.nextName();
|
String name = reader.nextName();
|
||||||
BoundField field = map.get(name);
|
BoundField field = map.get(name);
|
||||||
if (field == null) {
|
if (field == null || !field.deserialized) {
|
||||||
// TODO: define a better policy
|
// TODO: define a better policy
|
||||||
reader.skipValue();
|
reader.skipValue();
|
||||||
} else {
|
} else {
|
||||||
@ -83,8 +83,10 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
|||||||
writer.beginObject();
|
writer.beginObject();
|
||||||
try {
|
try {
|
||||||
for (BoundField boundField : boundFields) {
|
for (BoundField boundField : boundFields) {
|
||||||
writer.name(boundField.name);
|
if (boundField.serialized) {
|
||||||
boundField.write(writer, value);
|
writer.name(boundField.name);
|
||||||
|
boundField.write(writer, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new AssertionError();
|
throw new AssertionError();
|
||||||
@ -93,9 +95,9 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static BoundField createBoundField(
|
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...
|
// 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);
|
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
|
||||||
@SuppressWarnings("unchecked") // the type adapter and field type always agree
|
@SuppressWarnings("unchecked") // the type adapter and field type always agree
|
||||||
@Override void write(JsonWriter writer, Object value)
|
@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 static class FactoryImpl implements Factory {
|
||||||
public boolean skipField(Class<?> declaringClazz, Field f, Type declaringType) {
|
public boolean serializeField(Class<?> declaringClazz, Field f, Type declaringType) {
|
||||||
return false;
|
return true;
|
||||||
|
}
|
||||||
|
public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaringType) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
|
||||||
Class<? super T> raw = type.getRawType();
|
Class<? super T> raw = type.getRawType();
|
||||||
@ -139,13 +144,14 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
|||||||
Type declaredType = type.getType();
|
Type declaredType = type.getType();
|
||||||
while (raw != Object.class) {
|
while (raw != Object.class) {
|
||||||
for (Field field : raw.getDeclaredFields()) {
|
for (Field field : raw.getDeclaredFields()) {
|
||||||
if (skipField(raw, field, declaredType)) {
|
boolean serialize = serializeField(raw, field, declaredType);
|
||||||
continue;
|
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()));
|
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
|
||||||
raw = type.getRawType();
|
raw = type.getRawType();
|
||||||
@ -156,9 +162,13 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
|||||||
|
|
||||||
static abstract class BoundField {
|
static abstract class BoundField {
|
||||||
final String name;
|
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.name = name;
|
||||||
|
this.serialized = serialized;
|
||||||
|
this.deserialized = deserialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
|
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.
|
* 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 static final Factory FACTORY = new Factory() {
|
||||||
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> typeToken) {
|
||||||
Type type = typeToken.getType();
|
Type type = typeToken.getType();
|
||||||
|
@ -24,7 +24,7 @@ import java.io.IOException;
|
|||||||
/**
|
/**
|
||||||
* Type adapters for basic types.
|
* Type adapters for basic types.
|
||||||
*/
|
*/
|
||||||
final class TypeAdapters {
|
public final class TypeAdapters {
|
||||||
private TypeAdapters() {}
|
private TypeAdapters() {}
|
||||||
|
|
||||||
public static final TypeAdapter<Boolean> BOOLEAN = new TypeAdapter<Boolean>() {
|
public static final TypeAdapter<Boolean> BOOLEAN = new TypeAdapter<Boolean>() {
|
||||||
|
Loading…
Reference in New Issue
Block a user