Unsafe allocation for reflective type adapters.

This commit is contained in:
Jesse Wilson 2011-08-03 01:25:51 +00:00
parent b922500c23
commit 98aa124589
3 changed files with 23 additions and 10 deletions

View File

@ -18,6 +18,7 @@ package com.google.gson;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.UnsafeAllocator;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Type; import java.lang.reflect.Type;

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson.internal;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
@ -27,7 +27,7 @@ import java.lang.reflect.Method;
* @author Joel Leitch * @author Joel Leitch
* @author Jesse Wilson * @author Jesse Wilson
*/ */
abstract class UnsafeAllocator { public abstract class UnsafeAllocator {
public abstract <T> T newInstance(Class<T> c) throws Exception; public abstract <T> T newInstance(Class<T> c) throws Exception;
public static UnsafeAllocator create() { public static UnsafeAllocator create() {

View File

@ -17,6 +17,7 @@
package com.google.gson.internal.bind; package com.google.gson.internal.bind;
import com.google.gson.internal.$Gson$Types; import com.google.gson.internal.$Gson$Types;
import com.google.gson.internal.UnsafeAllocator;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonToken;
@ -35,24 +36,37 @@ import java.util.Map;
public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> { public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
public static final Factory FACTORY = new FactoryImpl(); public static final Factory FACTORY = new FactoryImpl();
private static final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create();
private final Class<? super T> rawType;
private final Constructor<? super T> constructor; private final Constructor<? super T> constructor;
private final Map<String, BoundField> map; private final Map<String, BoundField> map;
private final BoundField[] boundFields; private final BoundField[] boundFields;
ReflectiveTypeAdapter(Constructor<? super T> constructor, Map<String, BoundField> map) { ReflectiveTypeAdapter(Class<? super T> rawType, Constructor<? super T> constructor, Map<String, BoundField> map) {
this.rawType = rawType;
this.constructor = constructor; this.constructor = constructor;
this.map = map; this.map = map;
this.boundFields = map.values().toArray(new BoundField[map.size()]); this.boundFields = map.values().toArray(new BoundField[map.size()]);
} }
@SuppressWarnings("unchecked") // the '? super T' is a raw T (the only kind we can construct)
public T read(JsonReader reader) throws IOException { public T read(JsonReader reader) throws IOException {
if (reader.peek() == JsonToken.NULL) { if (reader.peek() == JsonToken.NULL) {
reader.nextNull(); // TODO: does this belong here? reader.nextNull(); // TODO: does this belong here?
return null; return null;
} }
@SuppressWarnings("unchecked") // the '? super T' is a raw T (the only kind we can construct) T instance;
T instance = (T) MiniGson.newInstance(constructor); if (constructor != null) {
instance = (T) MiniGson.newInstance(constructor);
} else {
try {
instance = (T) unsafeAllocator.newInstance(rawType);
} catch (Exception e) {
throw new RuntimeException(("Unable to invoke no-args constructor for " + rawType.getName()
+ ". Register an InstanceCreator with Gson for this type may fix this problem."), e);
}
}
// TODO: null out the other fields? // TODO: null out the other fields?
@ -128,15 +142,13 @@ public final class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
return null; // it's a primitive! return null; // it's a primitive!
} }
// TODO: use Joel's constructor calling code (with setAccessible) Constructor<? super T> constructor = null;
Constructor<? super T> constructor;
try { try {
constructor = raw.getDeclaredConstructor(); constructor = raw.getDeclaredConstructor();
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException ignored) {
return null;
} }
return new ReflectiveTypeAdapter<T>(constructor, getBoundFields(context, type, raw)); return new ReflectiveTypeAdapter<T>(raw, constructor, getBoundFields(context, type, raw));
} }
private Map<String, BoundField> getBoundFields( private Map<String, BoundField> getBoundFields(