From bf4ab04413ce091971175ff594c794116925b44a Mon Sep 17 00:00:00 2001 From: Inderjeet Singh Date: Fri, 1 Apr 2011 23:54:41 +0000 Subject: [PATCH] replaced multiple caches in ReflectingFieldNavigator with a single one. Two additional optimizations: - storing the field list for the entire type hierarchy in the cache instead of navigating it every time. - storing the resolved type for the field in FieldAttributes instead of using reflection every time. --- .../java/com/google/gson/FieldAttributes.java | 31 ++++- .../google/gson/ReflectingFieldNavigator.java | 109 +++++++----------- 2 files changed, 73 insertions(+), 67 deletions(-) diff --git a/gson/src/main/java/com/google/gson/FieldAttributes.java b/gson/src/main/java/com/google/gson/FieldAttributes.java index 9b30ea18..c175db7a 100644 --- a/gson/src/main/java/com/google/gson/FieldAttributes.java +++ b/gson/src/main/java/com/google/gson/FieldAttributes.java @@ -17,6 +17,7 @@ package com.google.gson; import com.google.gson.internal.$Preconditions; +import com.google.gson.internal.$Types; import java.lang.annotation.Annotation; import java.lang.reflect.Field; @@ -48,23 +49,30 @@ public final class FieldAttributes { private final boolean isSynthetic; private final int modifiers; private final String name; + private final Type resolvedType; // Fields used for lazy initialization private Type genericType; private Collection annotations; + FieldAttributes(Class declaringClazz, Field f) { + this(declaringClazz, f, declaringClazz); + } + /** * Constructs a Field Attributes object from the {@code f}. * * @param f the field to pull attributes from + * @param declaringType The type in which the field is declared */ - FieldAttributes(final Class declaringClazz, final Field f) { + FieldAttributes(Class declaringClazz, Field f, Type declaringType) { this.declaringClazz = $Preconditions.checkNotNull(declaringClazz); this.name = f.getName(); this.declaredType = f.getType(); this.isSynthetic = f.isSynthetic(); this.modifiers = f.getModifiers(); this.field = f; + this.resolvedType = getTypeInfoForField(f, declaringType); } private static int getMaxCacheSize() { @@ -217,6 +225,10 @@ public final class FieldAttributes { return field; } + Type getResolvedType() { + return resolvedType; + } + @SuppressWarnings("unchecked") private static T getAnnotationFromArray( Collection annotations, Class annotation) { @@ -227,4 +239,21 @@ public final class FieldAttributes { } return null; } + + /** + * Evaluates the "actual" type for the field. If the field is a "TypeVariable" or has a + * "TypeVariable" in a parameterized type then it evaluates the real type. + * + * @param f the actual field object to retrieve the type from + * @param typeDefiningF the type that contains the field {@code f} + * @return the type information for the field + */ + public static Type getTypeInfoForField(Field f, Type typeDefiningF) { + Class rawType = $Types.getRawType(typeDefiningF); + if (!f.getDeclaringClass().isAssignableFrom(rawType)) { + // this field is unrelated to the type; the user probably omitted type information + return f.getGenericType(); + } + return $Types.resolve(typeDefiningF, rawType, f.getGenericType()); + } } diff --git a/gson/src/main/java/com/google/gson/ReflectingFieldNavigator.java b/gson/src/main/java/com/google/gson/ReflectingFieldNavigator.java index d125049c..55e71698 100644 --- a/gson/src/main/java/com/google/gson/ReflectingFieldNavigator.java +++ b/gson/src/main/java/com/google/gson/ReflectingFieldNavigator.java @@ -33,10 +33,9 @@ import java.util.List; * @author Jesse Wilson */ final class ReflectingFieldNavigator { - private static final LruCache>> classCache = - new LruCache>>(500); - private static final LruCache, Field[]> fieldsCache = - new LruCache, Field[]>(500); + + private static final LruCache> fieldsCache = + new LruCache>(500); private final ExclusionStrategy exclusionStrategy; @@ -53,77 +52,55 @@ final class ReflectingFieldNavigator { * @param visitor the visitor to visit each field with */ void visitFieldsReflectively(ObjectTypePair objTypePair, Visitor visitor) { - for (Class curr : getInheritanceHierarchy(objTypePair.getMoreSpecificType())) { - navigateClassFields(objTypePair.getObject(), objTypePair.type, curr, visitor); + Type moreSpecificType = objTypePair.getMoreSpecificType(); + Object obj = objTypePair.getObject(); + for (FieldAttributes fieldAttributes : getAllFields(moreSpecificType, objTypePair.getType())) { + if (exclusionStrategy.shouldSkipField(fieldAttributes) + || exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) { + continue; // skip + } + Type resolvedTypeOfField = fieldAttributes.getResolvedType(); + boolean visitedWithCustomHandler = + visitor.visitFieldUsingCustomHandler(fieldAttributes, resolvedTypeOfField, obj); + if (!visitedWithCustomHandler) { + if ($Types.isArray(resolvedTypeOfField)) { + visitor.visitArrayField(fieldAttributes, resolvedTypeOfField, obj); + } else { + visitor.visitObjectField(fieldAttributes, resolvedTypeOfField, obj); + } + } } } + private List getAllFields(Type type, Type declaredType) { + List fields = fieldsCache.get(type); + if (fields == null) { + fields = new ArrayList(); + for (Class curr : getInheritanceHierarchy(type)) { + Field[] fields1 = curr.getDeclaredFields(); + AccessibleObject.setAccessible(fields1, true); + Field[] classFields = fields1; + for (Field f : classFields) { + fields.add(new FieldAttributes(curr, f, declaredType)); + } + } + fieldsCache.addElement(type, fields); + } + return fields; + } + /** * Returns a list of classes corresponding to the inheritance of specified type */ private List> getInheritanceHierarchy(Type type) { - List> classes = classCache.get(type); - if (classes == null) { - classes = new ArrayList>(); - Class topLevelClass = $Types.getRawType(type); - for (Class curr = topLevelClass; curr != null && !curr.equals(Object.class); curr = - curr.getSuperclass()) { - if (!curr.isSynthetic()) { - classes.add(curr); - } + List> classes = new ArrayList>(); + Class topLevelClass = $Types.getRawType(type); + for (Class curr = topLevelClass; curr != null && !curr.equals(Object.class); curr = + curr.getSuperclass()) { + if (!curr.isSynthetic()) { + classes.add(curr); } - classCache.put(type, classes); } return classes; } - - private void navigateClassFields(Object obj, Type objType, - Class classInInheritanceHierarchyForObj, Visitor visitor) { - Field[] fields = getFields(classInInheritanceHierarchyForObj); - for (Field f : fields) { - FieldAttributes fieldAttributes = new FieldAttributes(classInInheritanceHierarchyForObj, f); - if (exclusionStrategy.shouldSkipField(fieldAttributes) - || exclusionStrategy.shouldSkipClass(fieldAttributes.getDeclaredClass())) { - continue; // skip - } - Type declaredTypeOfField = getTypeInfoForField(f, objType); - boolean visitedWithCustomHandler = - visitor.visitFieldUsingCustomHandler(fieldAttributes, declaredTypeOfField, obj); - if (!visitedWithCustomHandler) { - if ($Types.isArray(declaredTypeOfField)) { - visitor.visitArrayField(fieldAttributes, declaredTypeOfField, obj); - } else { - visitor.visitObjectField(fieldAttributes, declaredTypeOfField, obj); - } - } - } - } - - private Field[] getFields(Class clazz) { - Field[] fields = fieldsCache.get(clazz); - if (fields == null) { - fields = clazz.getDeclaredFields(); - AccessibleObject.setAccessible(fields, true); - fieldsCache.put(clazz, fields); - } - return fields; - } - - - /** - * Evaluates the "actual" type for the field. If the field is a "TypeVariable" or has a - * "TypeVariable" in a parameterized type then it evaluates the real type. - * - * @param f the actual field object to retrieve the type from - * @param typeDefiningF the type that contains the field {@code f} - * @return the type information for the field - */ - public static Type getTypeInfoForField(Field f, Type typeDefiningF) { - Class rawType = $Types.getRawType(typeDefiningF); - if (!f.getDeclaringClass().isAssignableFrom(rawType)) { - // this field is unrelated to the type; the user probably omitted type information - return f.getGenericType(); - } - return $Types.resolve(typeDefiningF, rawType, f.getGenericType()); - } }