Why not lazy initialization boundFields in ReflectiveTypeAdapterFactory.Adapter?
- Dominant language
- Java
- Stars
- 24.2k
- Forks
- 4.5k
- Avg merge
- 6d 4h
- Merged PRs (30d)
- 12
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:
```Java
// 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;
}
}
```
```Json
{
"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?
```Java
@Override
public TypeAdapter create(Gson gson, final TypeToken type) {
Class 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 constructor = constructorConstructor.get(type);
return new LazyReflectiveTypeAdapterFactory.Adapter<>(constructor, new LazyInitBoundFiledCallback() {
@Override
public Map call() {
return getBoundFields(gson, type, raw, blockInaccessible);
}
});
}
public static final class Adapter extends TypeAdapter {
private final ObjectConstructor constructor;
private final LazyInitBoundFiledCallback lazyInitBoundFiledCallback;
private volatile Map boundFields;
Adapter(ObjectConstructor 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 call();
}
```
Contributor guide
Assessment
This issue has not been assessed yet.