Using serializationExclusionStrategy while navigating through fields to decide which ones to skip.
This commit is contained in:
parent
37abcf3637
commit
3331dcdab0
|
@ -16,23 +16,26 @@
|
||||||
|
|
||||||
package com.google.gson;
|
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.MiniGson;
|
||||||
|
import com.google.gson.internal.bind.ReflectiveTypeAdapter;
|
||||||
import com.google.gson.internal.bind.TypeAdapter;
|
import com.google.gson.internal.bind.TypeAdapter;
|
||||||
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;
|
||||||
import com.google.gson.stream.JsonWriter;
|
import com.google.gson.stream.JsonWriter;
|
||||||
import com.google.gson.stream.MalformedJsonException;
|
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
|
* 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
|
serializeNulls
|
||||||
serializers
|
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()
|
this.miniGson = new MiniGson.Builder()
|
||||||
|
.factory(factory)
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,42 +31,8 @@ import java.util.Map;
|
||||||
/**
|
/**
|
||||||
* Adapts the fields of an object to the properties of a JSON object.
|
* Adapts the fields of an object to the properties of a JSON object.
|
||||||
*/
|
*/
|
||||||
final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
|
||||||
public static final Factory FACTORY = new Factory() {
|
public static final Factory FACTORY = new FactoryImpl();
|
||||||
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;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Constructor<? super T> constructor;
|
private final Constructor<? super T> constructor;
|
||||||
private final Map<String, BoundField> map;
|
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 {
|
static abstract class BoundField {
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user