Skip to content

Commit 4b04267

Browse files
committed
Cleanup after experimenting with specializing BoundField by type (ie. Field.setInt() to avoid autoboxing)
1 parent 3c4d121 commit 4b04267

File tree

3 files changed

+53
-50
lines changed

3 files changed

+53
-50
lines changed

extras/src/main/java/com/google/gson/mini/MiniGson.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ public final class MiniGson {
5050

5151
private MiniGson(Builder builder) {
5252
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
53-
factories.addAll(builder.factories);
5453
factories.add(TypeAdapters.BOOLEAN_FACTORY);
5554
factories.add(TypeAdapters.INTEGER_FACTORY);
5655
factories.add(TypeAdapters.DOUBLE_FACTORY);
5756
factories.add(TypeAdapters.LONG_FACTORY);
5857
factories.add(TypeAdapters.STRING_FACTORY);
58+
factories.addAll(builder.factories);
5959
factories.add(CollectionTypeAdapter.FACTORY);
6060
factories.add(StringToValueMapTypeAdapter.FACTORY);
6161
factories.add(ArrayTypeAdapter.FACTORY);
@@ -66,7 +66,8 @@ private MiniGson(Builder builder) {
6666
// TODO: this should use Joel's unsafe constructor stuff
6767
static <T> T newInstance(Constructor<T> constructor) {
6868
try {
69-
return constructor.newInstance();
69+
Object[] args = null;
70+
return constructor.newInstance(args);
7071
} catch (InstantiationException e) {
7172
// TODO: JsonParseException ?
7273
throw new RuntimeException(e);
@@ -90,7 +91,7 @@ public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
9091

9192
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
9293
@SuppressWarnings("unchecked") // the key and value type parameters always agree
93-
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
94+
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
9495
if (ongoingCall != null) {
9596
return ongoingCall;
9697
}

extras/src/main/java/com/google/gson/mini/ReflectiveTypeAdapter.java

Lines changed: 49 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,14 @@ public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
5151
return new ReflectiveTypeAdapter<T>(constructor, getBoundFields(context, type, raw));
5252
}
5353

54-
private Map<String, BoundField<?>> getBoundFields(
54+
private Map<String, BoundField> getBoundFields(
5555
MiniGson context, TypeToken<?> type, Class<?> raw) {
56-
Map<String, BoundField<?>> result = new LinkedHashMap<String, BoundField<?>>();
56+
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
5757
while (raw != Object.class) {
5858
for (Field field : raw.getDeclaredFields()) {
5959
field.setAccessible(true); // TODO: don't call setAccessible unless necessary
6060
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
61-
BoundField<?> boundField = BoundField.create(context, field, TypeToken.get(fieldType));
61+
BoundField boundField = createBoundField(context, field, TypeToken.get(fieldType));
6262
result.put(boundField.name, boundField);
6363
}
6464
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
@@ -69,13 +69,13 @@ private Map<String, BoundField<?>> getBoundFields(
6969
};
7070

7171
private final Constructor<? super T> constructor;
72-
private final Map<String, BoundField<?>> map;
73-
private final BoundField<?>[] boundFields;
72+
private final Map<String, BoundField> map;
73+
private final BoundField[] boundFields;
7474

75-
ReflectiveTypeAdapter(Constructor<? super T> constructor, Map<String, BoundField<?>> map) {
75+
ReflectiveTypeAdapter(Constructor<? super T> constructor, Map<String, BoundField> map) {
7676
this.constructor = constructor;
7777
this.map = map;
78-
this.boundFields = map.values().toArray(new BoundField<?>[map.size()]);
78+
this.boundFields = map.values().toArray(new BoundField[map.size()]);
7979
}
8080

8181
public T read(JsonReader reader) throws IOException {
@@ -90,15 +90,19 @@ public T read(JsonReader reader) throws IOException {
9090
// TODO: null out the other fields?
9191

9292
reader.beginObject();
93-
while (reader.hasNext()) {
94-
String name = reader.nextName();
95-
BoundField<?> field = map.get(name);
96-
if (field == null) {
97-
// TODO: define a better policy
98-
reader.skipValue();
99-
} else {
100-
field.read(reader, instance);
93+
try {
94+
while (reader.hasNext()) {
95+
String name = reader.nextName();
96+
BoundField field = map.get(name);
97+
if (field == null) {
98+
// TODO: define a better policy
99+
reader.skipValue();
100+
} else {
101+
field.read(reader, instance);
102+
}
101103
}
104+
} catch (IllegalAccessException e) {
105+
throw new AssertionError();
102106
}
103107
reader.endObject();
104108
return instance;
@@ -111,45 +115,44 @@ public void write(JsonWriter writer, T value) throws IOException {
111115
}
112116

113117
writer.beginObject();
114-
for (BoundField<?> boundField : boundFields) {
115-
writer.name(boundField.name);
116-
boundField.write(writer, value);
118+
try {
119+
for (BoundField boundField : boundFields) {
120+
writer.name(boundField.name);
121+
boundField.write(writer, value);
122+
}
123+
} catch (IllegalAccessException e) {
124+
throw new AssertionError();
117125
}
118126
writer.endObject();
119127
}
120128

121-
static class BoundField<T> {
129+
static BoundField createBoundField(
130+
final MiniGson context, final Field field, final TypeToken<?> fieldType) {
131+
// special casing primitives here saves ~5% on Android...
132+
return new BoundField(field.getName()) {
133+
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
134+
@SuppressWarnings("unchecked") // the type adapter and field type always agree
135+
@Override void write(JsonWriter writer, Object value)
136+
throws IOException, IllegalAccessException {
137+
Object fieldValue = field.get(value);
138+
((TypeAdapter) typeAdapter).write(writer, fieldValue);
139+
}
140+
@Override void read(JsonReader reader, Object value)
141+
throws IOException, IllegalAccessException {
142+
Object fieldValue = typeAdapter.read(reader);
143+
field.set(value, fieldValue);
144+
}
145+
};
146+
}
147+
148+
static abstract class BoundField {
122149
final String name;
123-
final Field field;
124-
final TypeAdapter<T> typeAdapter;
125150

126-
BoundField(String name, Field field, TypeAdapter<T> typeAdapter) {
151+
protected BoundField(String name) {
127152
this.name = name;
128-
this.field = field;
129-
this.typeAdapter = typeAdapter;
130-
}
131-
132-
static <T> BoundField<T> create(MiniGson context, Field field, TypeToken<T> fieldType) {
133-
return new BoundField<T>(field.getName(), field, context.getAdapter(fieldType));
134153
}
135154

136-
void write(JsonWriter writer, Object value) throws IOException {
137-
try {
138-
@SuppressWarnings("unchecked") // we previously verified that field is of type T
139-
T fieldValue = (T) field.get(value);
140-
typeAdapter.write(writer, fieldValue);
141-
} catch (IllegalAccessException e) {
142-
throw new AssertionError();
143-
}
144-
}
145-
146-
void read(JsonReader reader, Object value) throws IOException {
147-
T fieldValue = typeAdapter.read(reader);
148-
try {
149-
field.set(value, fieldValue);
150-
} catch (IllegalAccessException e) {
151-
throw new AssertionError();
152-
}
153-
}
155+
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
156+
abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
154157
}
155158
}

extras/src/test/java/com/google/gson/mini/MiniGsonTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import junit.framework.TestCase;
2929

3030
public final class MiniGsonTest extends TestCase {
31-
3231
private MiniGson miniGson = new MiniGson.Builder().build();
3332
private TypeAdapter<Truck> truckAdapter = miniGson.getAdapter(Truck.class);
3433
private TypeAdapter<Map<String, Double>> mapAdapter

0 commit comments

Comments
 (0)