From 4b042671af018f308c2a261145dc6712e39b96e7 Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Fri, 15 Jul 2011 14:37:05 +0000 Subject: [PATCH] Cleanup after experimenting with specializing BoundField by type (ie. Field.setInt() to avoid autoboxing) --- .../java/com/google/gson/mini/MiniGson.java | 7 +- .../gson/mini/ReflectiveTypeAdapter.java | 95 ++++++++++--------- .../com/google/gson/mini/MiniGsonTest.java | 1 - 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/extras/src/main/java/com/google/gson/mini/MiniGson.java b/extras/src/main/java/com/google/gson/mini/MiniGson.java index 47b99e680a..d22cf1a642 100644 --- a/extras/src/main/java/com/google/gson/mini/MiniGson.java +++ b/extras/src/main/java/com/google/gson/mini/MiniGson.java @@ -50,12 +50,12 @@ public final class MiniGson { private MiniGson(Builder builder) { List factories = new ArrayList(); - 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); @@ -66,7 +66,8 @@ private MiniGson(Builder builder) { // TODO: this should use Joel's unsafe constructor stuff static T newInstance(Constructor constructor) { try { - return constructor.newInstance(); + Object[] args = null; + return constructor.newInstance(args); } catch (InstantiationException e) { // TODO: JsonParseException ? throw new RuntimeException(e); @@ -90,7 +91,7 @@ public TypeAdapter getAdapter(TypeToken type) { Map, FutureTypeAdapter> threadCalls = calls.get(); @SuppressWarnings("unchecked") // the key and value type parameters always agree - FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type); + FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; } diff --git a/extras/src/main/java/com/google/gson/mini/ReflectiveTypeAdapter.java b/extras/src/main/java/com/google/gson/mini/ReflectiveTypeAdapter.java index 04d416bef5..621aa4368a 100644 --- a/extras/src/main/java/com/google/gson/mini/ReflectiveTypeAdapter.java +++ b/extras/src/main/java/com/google/gson/mini/ReflectiveTypeAdapter.java @@ -51,14 +51,14 @@ public TypeAdapter create(MiniGson context, TypeToken type) { return new ReflectiveTypeAdapter(constructor, getBoundFields(context, type, raw)); } - private Map> getBoundFields( + private Map getBoundFields( MiniGson context, TypeToken type, Class raw) { - Map> result = new LinkedHashMap>(); + Map result = new LinkedHashMap(); 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())); @@ -69,13 +69,13 @@ private Map> getBoundFields( }; private final Constructor constructor; - private final Map> map; - private final BoundField[] boundFields; + private final Map map; + private final BoundField[] boundFields; - ReflectiveTypeAdapter(Constructor constructor, Map> map) { + ReflectiveTypeAdapter(Constructor constructor, Map 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 { @@ -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; @@ -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 { + 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 typeAdapter; - BoundField(String name, Field field, TypeAdapter typeAdapter) { + protected BoundField(String name) { this.name = name; - this.field = field; - this.typeAdapter = typeAdapter; - } - - static BoundField create(MiniGson context, Field field, TypeToken fieldType) { - return new BoundField(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; } } diff --git a/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java b/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java index f0591adf33..ccc2ba223a 100644 --- a/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java +++ b/extras/src/test/java/com/google/gson/mini/MiniGsonTest.java @@ -28,7 +28,6 @@ import junit.framework.TestCase; public final class MiniGsonTest extends TestCase { - private MiniGson miniGson = new MiniGson.Builder().build(); private TypeAdapter truckAdapter = miniGson.getAdapter(Truck.class); private TypeAdapter> mapAdapter