Using serializationExclusionStrategy while navigating through fields to decide which ones to skip.

This commit is contained in:
Inderjeet Singh 2011-08-03 00:47:36 +00:00
parent 37abcf3637
commit 3331dcdab0
2 changed files with 68 additions and 46 deletions

View File

@ -16,23 +16,26 @@
package com.google.gson;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.google.gson.internal.bind.MiniGson;
import com.google.gson.internal.bind.ReflectiveTypeAdapter;
import com.google.gson.internal.bind.TypeAdapter;
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 com.google.gson.stream.MalformedJsonException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* This is the main class for using Gson. Gson is typically used by first constructing a
@ -180,7 +183,17 @@ public final class Gson {
serializeNulls
serializers
*/
TypeAdapter.Factory factory = new ReflectiveTypeAdapter.FactoryImpl() {
@Override
public boolean skipField(Class<?> declaringClazz, Field f, Type declaredType) {
// TODO: support deserialization policy as well
return Gson.this.serializationExclusionStrategy.shouldSkipField(
new FieldAttributes(declaringClazz, f, declaredType));
}
};
this.miniGson = new MiniGson.Builder()
.factory(factory)
.build();
}

View File

@ -31,42 +31,8 @@ import java.util.Map;
/**
* Adapts the fields of an object to the properties of a JSON object.
*/
final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
public static final Factory FACTORY = new Factory() {
public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
// TODO: use Joel's constructor calling code (with setAccessible)
Constructor<? super T> constructor;
try {
constructor = raw.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
return null;
}
return new ReflectiveTypeAdapter<T>(constructor, getBoundFields(context, type, raw));
}
private Map<String, BoundField> getBoundFields(
MiniGson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
while (raw != Object.class) {
for (Field field : raw.getDeclaredFields()) {
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();
}
return result;
}
};
public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
public static final Factory FACTORY = new FactoryImpl();
private final Constructor<? super T> constructor;
private final Map<String, BoundField> map;
@ -145,6 +111,49 @@ 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 <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
// TODO: use Joel's constructor calling code (with setAccessible)
Constructor<? super T> constructor;
try {
constructor = raw.getDeclaredConstructor();
} catch (NoSuchMethodException e) {
return null;
}
return new ReflectiveTypeAdapter<T>(constructor, getBoundFields(context, type, raw));
}
private Map<String, BoundField> getBoundFields(
MiniGson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
Type declaredType = type.getType();
while (raw != Object.class) {
for (Field field : raw.getDeclaredFields()) {
if (skipField(raw, field, declaredType)) {
continue;
}
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();
}
return result;
}
}
static abstract class BoundField {
final String name;