diff --git a/gson/src/main/java/com/google/gson/MappedObjectConstructor.java b/gson/src/main/java/com/google/gson/MappedObjectConstructor.java index 25654b67..a752ef05 100644 --- a/gson/src/main/java/com/google/gson/MappedObjectConstructor.java +++ b/gson/src/main/java/com/google/gson/MappedObjectConstructor.java @@ -16,6 +16,7 @@ package com.google.gson; +import com.google.gson.internal.LruCache; import com.google.gson.internal.Types; import com.google.gson.internal.UnsafeAllocator; @@ -36,7 +37,22 @@ import java.lang.reflect.Type; final class MappedObjectConstructor implements ObjectConstructor { private static final UnsafeAllocator unsafeAllocator = UnsafeAllocator.create(); + private static final LruCache, Constructor> noArgsConstructorsCache = + new LruCache, Constructor>(500); private final ParameterizedTypeHandlerMap> instanceCreatorMap; + /** + * We need a special null value to indicate that the class does not have a no-args constructor. + * This helps avoid using reflection over and over again for such classes. For convenience, we + * use the no-args constructor of this class itself since this class would never be + * deserialized using Gson. + */ + private static final Constructor NULL_VALUE = + getNoArgsConstructorUsingReflection(MappedObjectConstructor.class); + + @SuppressWarnings("unused") + private MappedObjectConstructor() { + this(null); + } public MappedObjectConstructor( ParameterizedTypeHandlerMap> instanceCreators) { @@ -71,13 +87,27 @@ final class MappedObjectConstructor implements ObjectConstructor { } private Constructor getNoArgsConstructor(Class clazz) { - try { - Constructor declaredConstructor = clazz.getDeclaredConstructor(); - declaredConstructor.setAccessible(true); - return declaredConstructor; - } catch (Exception e) { + @SuppressWarnings("unchecked") + Constructor constructor = (Constructor)noArgsConstructorsCache.getElement(clazz); + if (constructor == NULL_VALUE) { return null; } + if (constructor == null) { + constructor = getNoArgsConstructorUsingReflection(clazz); + noArgsConstructorsCache.addElement(clazz, constructor); + } + return constructor == NULL_VALUE ? null : constructor; + } + + @SuppressWarnings("unchecked") + private static Constructor getNoArgsConstructorUsingReflection(Class clazz) { + try { + Constructor constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + return constructor; + } catch (Exception e) { + return (Constructor) NULL_VALUE; + } } @Override