-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Open
Labels
Description
In the latest code which commit is cbc0af867b898d9e8244f268f4ffe37dfcaf8ea7
, ReflectiveTypeAdapterFactory.Adapter
needs boundFields
in its construct and the getBoundFields
method will collect all fileds. But in some case, maybe we don't need collect all boundFileds to serialize or deserialize. In below example, the json string just contains userFiled
, thus create bound filed with Article
is redundant and will increate cost time.
Example:
// Complex Model
public class ComplexModel {
private User userFiled;
private Article article;
private String stringFiled;
private static class User {
private String aFiled;
private String bFile;
}
private static class Article {
private User userFiled;
private String aFiled;
private String bFile;
}
}
{
"userFiled": {
"aFiled": "",
"bFiled": ""
}
}
I think the better way is to create boundfiled on deman. Maybe lazy initialization can improve performance, especially for mobile platforms such as Android. I didn't read the entire code, is there any other consideration for not doing this?
@Override
public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
ReflectionAccessFilter.FilterResult filterResult = ReflectionAccessFilterHelper.getFilterResult(reflectionFilters, raw);
if (filterResult == ReflectionAccessFilter.FilterResult.BLOCK_ALL) {
throw new JsonIOException("ReflectionAccessFilter does not permit using reflection for "
+ raw + ". Register a TypeAdapter for this type or adjust the access filter.");
}
boolean blockInaccessible = filterResult == ReflectionAccessFilter.FilterResult.BLOCK_INACCESSIBLE;
ObjectConstructor<T> constructor = constructorConstructor.get(type);
return new LazyReflectiveTypeAdapterFactory.Adapter<>(constructor, new LazyInitBoundFiledCallback() {
@Override
public Map<String, BoundField> call() {
return getBoundFields(gson, type, raw, blockInaccessible);
}
});
}
public static final class Adapter<T> extends TypeAdapter<T> {
private final ObjectConstructor<T> constructor;
private final LazyInitBoundFiledCallback lazyInitBoundFiledCallback;
private volatile Map<String, BoundField> boundFields;
Adapter(ObjectConstructor<T> constructor, LazyInitBoundFiledCallback lazyInitBoundFiledCallback) {
this.constructor = constructor;
this.lazyInitBoundFiledCallback = lazyInitBoundFiledCallback;
}
private void ensure() {
if (boundFields == null) {
synchronized (this) {
if (boundFields == null) {
boundFields = lazyInitBoundFiledCallback.call();
}
}
}
}
@Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
T instance = constructor.construct();
ensure();
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
field.read(in, instance);
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e);
}
in.endObject();
return instance;
}
@Override
public void write(JsonWriter out, T value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
ensure();
out.beginObject();
try {
for (BoundField boundField : boundFields.values()) {
boundField.write(out, value);
}
} catch (IllegalAccessException e) {
throw ReflectionHelper.createExceptionForUnexpectedIllegalAccess(e);
}
out.endObject();
}
}
interface LazyInitBoundFiledCallback {
Map<String, BoundField> call();
}