Skip to content

Commit

Permalink
Cleanup after experimenting with specializing BoundField by type (ie.…
Browse files Browse the repository at this point in the history
… Field.setInt() to avoid autoboxing)
  • Loading branch information
swankjesse committed Jul 15, 2011
1 parent 3c4d121 commit 4b04267
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 50 deletions.
7 changes: 4 additions & 3 deletions extras/src/main/java/com/google/gson/mini/MiniGson.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ public final class MiniGson {

private MiniGson(Builder builder) {
List<TypeAdapter.Factory> factories = new ArrayList<TypeAdapter.Factory>();
factories.addAll(builder.factories);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.DOUBLE_FACTORY);
factories.add(TypeAdapters.LONG_FACTORY);
factories.add(TypeAdapters.STRING_FACTORY);
factories.addAll(builder.factories);
factories.add(CollectionTypeAdapter.FACTORY);
factories.add(StringToValueMapTypeAdapter.FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
Expand All @@ -66,7 +66,8 @@ private MiniGson(Builder builder) {
// TODO: this should use Joel's unsafe constructor stuff
static <T> T newInstance(Constructor<T> constructor) {
try {
return constructor.newInstance();
Object[] args = null;
return constructor.newInstance(args);
} catch (InstantiationException e) {
// TODO: JsonParseException ?
throw new RuntimeException(e);
Expand All @@ -90,7 +91,7 @@ public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {

Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
@SuppressWarnings("unchecked") // the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) {
return new ReflectiveTypeAdapter<T>(constructor, getBoundFields(context, type, raw));
}

private Map<String, BoundField<?>> getBoundFields(
private Map<String, BoundField> getBoundFields(
MiniGson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField<?>> result = new LinkedHashMap<String, BoundField<?>>();
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 = BoundField.create(context, field, TypeToken.get(fieldType));
BoundField boundField = createBoundField(context, field, TypeToken.get(fieldType));
result.put(boundField.name, boundField);
}
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
Expand All @@ -69,13 +69,13 @@ private Map<String, BoundField<?>> getBoundFields(
};

private final Constructor<? super T> constructor;
private final Map<String, BoundField<?>> map;
private final BoundField<?>[] boundFields;
private final Map<String, BoundField> map;
private final BoundField[] boundFields;

ReflectiveTypeAdapter(Constructor<? super T> constructor, Map<String, BoundField<?>> map) {
ReflectiveTypeAdapter(Constructor<? super T> constructor, Map<String, BoundField> map) {
this.constructor = constructor;
this.map = map;
this.boundFields = map.values().toArray(new BoundField<?>[map.size()]);
this.boundFields = map.values().toArray(new BoundField[map.size()]);
}

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

reader.beginObject();
while (reader.hasNext()) {
String name = reader.nextName();
BoundField<?> field = map.get(name);
if (field == null) {
// TODO: define a better policy
reader.skipValue();
} else {
field.read(reader, instance);
try {
while (reader.hasNext()) {
String name = reader.nextName();
BoundField field = map.get(name);
if (field == null) {
// TODO: define a better policy
reader.skipValue();
} else {
field.read(reader, instance);
}
}
} catch (IllegalAccessException e) {
throw new AssertionError();
}
reader.endObject();
return instance;
Expand All @@ -111,45 +115,44 @@ public void write(JsonWriter writer, T value) throws IOException {
}

writer.beginObject();
for (BoundField<?> boundField : boundFields) {
writer.name(boundField.name);
boundField.write(writer, value);
try {
for (BoundField boundField : boundFields) {
writer.name(boundField.name);
boundField.write(writer, value);
}
} catch (IllegalAccessException e) {
throw new AssertionError();
}
writer.endObject();
}

static class BoundField<T> {
static BoundField createBoundField(
final MiniGson context, final Field field, final TypeToken<?> fieldType) {
// special casing primitives here saves ~5% on Android...
return new BoundField(field.getName()) {
final TypeAdapter<?> typeAdapter = context.getAdapter(fieldType);
@SuppressWarnings("unchecked") // the type adapter and field type always agree
@Override void write(JsonWriter writer, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = field.get(value);
((TypeAdapter) typeAdapter).write(writer, fieldValue);
}
@Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = typeAdapter.read(reader);
field.set(value, fieldValue);
}
};
}

static abstract class BoundField {
final String name;
final Field field;
final TypeAdapter<T> typeAdapter;

BoundField(String name, Field field, TypeAdapter<T> typeAdapter) {
protected BoundField(String name) {
this.name = name;
this.field = field;
this.typeAdapter = typeAdapter;
}

static <T> BoundField<T> create(MiniGson context, Field field, TypeToken<T> fieldType) {
return new BoundField<T>(field.getName(), field, context.getAdapter(fieldType));
}

void write(JsonWriter writer, Object value) throws IOException {
try {
@SuppressWarnings("unchecked") // we previously verified that field is of type T
T fieldValue = (T) field.get(value);
typeAdapter.write(writer, fieldValue);
} catch (IllegalAccessException e) {
throw new AssertionError();
}
}

void read(JsonReader reader, Object value) throws IOException {
T fieldValue = typeAdapter.read(reader);
try {
field.set(value, fieldValue);
} catch (IllegalAccessException e) {
throw new AssertionError();
}
}
abstract void write(JsonWriter writer, Object value) throws IOException, IllegalAccessException;
abstract void read(JsonReader reader, Object value) throws IOException, IllegalAccessException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import junit.framework.TestCase;

public final class MiniGsonTest extends TestCase {

private MiniGson miniGson = new MiniGson.Builder().build();
private TypeAdapter<Truck> truckAdapter = miniGson.getAdapter(Truck.class);
private TypeAdapter<Map<String, Double>> mapAdapter
Expand Down

0 comments on commit 4b04267

Please sign in to comment.