diff options
author | Tatu Saloranta <tatu.saloranta@iki.fi> | 2015-09-21 09:52:45 -0700 |
---|---|---|
committer | Tatu Saloranta <tatu.saloranta@iki.fi> | 2015-09-21 09:52:45 -0700 |
commit | d6699257b2f60fd10251862870d73743f785acea (patch) | |
tree | c5d6399e630d1f7e1961c88fa09c35a92c9a6f37 | |
parent | cbb008c94f4ab236e83bfe01220e6de3fa509e07 (diff) | |
download | jackson-databind-d6699257b2f60fd10251862870d73743f785acea.tar.gz |
streamlining earlier perf improvements
5 files changed, 195 insertions, 61 deletions
diff --git a/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java b/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java index 4ef1c6d81..df0f3d20a 100644 --- a/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java +++ b/src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java @@ -6,6 +6,7 @@ import java.io.Serializable; import java.util.*; import com.fasterxml.jackson.core.*; +import com.fasterxml.jackson.databind.util.ClassUtil; /** * Checked exception used to signal fatal problems with mapping of @@ -101,9 +102,9 @@ public class JsonMappingException * butt-ugly for arrays. So let's use getSimpleName() instead; * but have to prepend package name too. */ - Package pkg = cls.getPackage(); - if (pkg != null) { - sb.append(pkg.getName()); + String pkgName = ClassUtil.getPackageName(cls); + if (pkgName != null) { + sb.append(pkgName); sb.append('.'); } sb.append(cls.getSimpleName()); diff --git a/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java b/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java index 94c324cd4..2f22c0239 100644 --- a/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java +++ b/src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.SerializationConfig; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.type.SimpleType; +import com.fasterxml.jackson.databind.util.ClassUtil; import com.fasterxml.jackson.databind.util.LRUMap; public class BasicClassIntrospector @@ -254,9 +255,8 @@ public class BasicClassIntrospector return false; } Class<?> raw = type.getRawClass(); - Package pkg = raw.getPackage(); - if (pkg != null) { - String pkgName = pkg.getName(); + String pkgName = ClassUtil.getPackageName(raw); + if (pkgName != null) { if (pkgName.startsWith("java.lang") || pkgName.startsWith("java.util")) { /* 23-Sep-2014, tatu: Should we be conservative here (minimal number diff --git a/src/main/java/com/fasterxml/jackson/databind/type/TypeBindings.java b/src/main/java/com/fasterxml/jackson/databind/type/TypeBindings.java index b25ab9d3b..6356a3d6c 100644 --- a/src/main/java/com/fasterxml/jackson/databind/type/TypeBindings.java +++ b/src/main/java/com/fasterxml/jackson/databind/type/TypeBindings.java @@ -4,6 +4,7 @@ import java.lang.reflect.*; import java.util.*; import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.util.ClassUtil; /** * Helper class used for resolving type parameters for given class @@ -138,8 +139,7 @@ public class TypeBindings * (honestly not sure what to do -- they are unbound for good, I think) */ if (_contextClass != null) { - Class<?> enclosing = _contextClass.getEnclosingClass(); - if (enclosing != null) { + if (ClassUtil.hasEnclosingClass(_contextClass)) { // [JACKSON-572]: Actually, let's skip this for all non-static inner classes // (which will also cover 'java.util' type cases... if (!Modifier.isStatic(_contextClass.getModifiers())) { @@ -148,10 +148,10 @@ public class TypeBindings // ... so this piece of code should not be needed any more /* - Package pkg = enclosing.getPackage(); - if (pkg != null) { + String pkgName = ClassUtil.getPackageName(enclosing); + if (pkgName != null) { // as per [JACKSON-533], also include "java.util.concurrent": - if (pkg.getName().startsWith("java.util")) { + if (pkgName.startsWith("java.util")) { return UNBOUND; } } diff --git a/src/main/java/com/fasterxml/jackson/databind/util/BeanUtil.java b/src/main/java/com/fasterxml/jackson/databind/util/BeanUtil.java index 0039b41bd..b552c827f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/BeanUtil.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/BeanUtil.java @@ -159,15 +159,14 @@ public class BeanUtil */ Class<?> compType = rt.getComponentType(); // Actually, let's just verify it's a "net.sf.cglib.*" class/interface - Package pkg = compType.getPackage(); - if (pkg != null) { - String pname = pkg.getName(); - if (pname.contains(".cglib")) { - if (pname.startsWith("net.sf.cglib") + String pkgName = ClassUtil.getPackageName(compType); + if (pkgName != null) { + if (pkgName.contains(".cglib")) { + if (pkgName.startsWith("net.sf.cglib") // also, as per [JACKSON-177] - || pname.startsWith("org.hibernate.repackage.cglib") + || pkgName.startsWith("org.hibernate.repackage.cglib") // and [core#674] - || pname.startsWith("org.springframework.cglib") + || pkgName.startsWith("org.springframework.cglib") ) { return true; } @@ -183,8 +182,8 @@ public class BeanUtil protected static boolean isGroovyMetaClassSetter(AnnotatedMethod am) { Class<?> argType = am.getRawParameterType(0); - Package pkg = argType.getPackage(); - if (pkg != null && pkg.getName().startsWith("groovy.lang")) { + String pkgName = ClassUtil.getPackageName(argType); + if (pkgName != null && pkgName.startsWith("groovy.lang")) { return true; } return false; @@ -199,8 +198,8 @@ public class BeanUtil if (rt == null || rt.isArray()) { return false; } - Package pkg = rt.getPackage(); - if (pkg != null && pkg.getName().startsWith("groovy.lang")) { + String pkgName = ClassUtil.getPackageName(rt); + if (pkgName != null && pkgName.startsWith("groovy.lang")) { return true; } return false; diff --git a/src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java b/src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java index 170f479d9..8b52c19c4 100644 --- a/src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java +++ b/src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java @@ -87,7 +87,7 @@ public final class ClassUtil */ try { // one more: method locals, anonymous, are not good: - if (type.getEnclosingMethod() != null) { + if (hasEnclosingMethod(type)) { return "local/anonymous"; } @@ -96,8 +96,8 @@ public final class ClassUtil * happens to be enclosing... but that gets convoluted) */ if (!allowNonStatic) { - if (type.getEnclosingClass() != null) { - if (!Modifier.isStatic(type.getModifiers())) { + if (!Modifier.isStatic(type.getModifiers())) { + if (hasEnclosingClass(type)) { return "non-static member class"; } } @@ -116,11 +116,11 @@ public final class ClassUtil // as above, GAE has some issues... try { // one more: method locals, anonymous, are not good: - if (type.getEnclosingMethod() != null) { + if (hasEnclosingMethod(type)) { return null; } if (!Modifier.isStatic(type.getModifiers())) { - return type.getEnclosingClass(); + return getEnclosingClass(type); } } catch (SecurityException e) { } catch (NullPointerException e) { } @@ -247,7 +247,7 @@ public final class ClassUtil /* /********************************************************** - /* Caching access to class annotations, hierarchy (2.7+) + /* Caching access to class metadata, added in 2.7 /********************************************************** */ @@ -259,51 +259,67 @@ public final class ClassUtil private final static Constructor<?>[] NO_CTORS = new Constructor<?>[0]; - private final static LRUMap<Class<?>,Class<?>[]> sInterfaces = new LRUMap<Class<?>,Class<?>[]>(40, 40); + private final static LRUMap<Class<?>,ClassMetadata> sCached = new LRUMap<Class<?>,ClassMetadata>(48, 48); - private final static LRUMap<Class<?>,Annotation[]> sClassAnnotations = new LRUMap<Class<?>,Annotation[]>(24, 24); + /** + * @since 2.7 + */ + public static String getPackageName(Class<?> cls) { + return _getMetadata(cls).getPackageName(); + } - private final static LRUMap<Class<?>,Constructor<?>[]> sConstructors = new LRUMap<Class<?>,Constructor<?>[]>(24, 24); + /** + * @since 2.7 + */ + public static boolean hasEnclosingClass(Class<?> cls) { + return _getMetadata(cls).getEnclosingClass() != null; + } /** * @since 2.7 */ - public static Annotation[] findClassAnnotations(Class<?> cls) - { - Annotation[] result = sClassAnnotations.get(cls); - if (result == null) { - result = cls.getDeclaredAnnotations(); - sClassAnnotations.putIfAbsent(cls, result); - } - return result; + public static Class<?> getEnclosingClass(Class<?> cls) { + return _getMetadata(cls).getEnclosingClass(); + } + + /** + * @since 2.7 + */ + public static boolean hasEnclosingMethod(Class<?> cls) { + return _getMetadata(cls).hasEnclosingMethod(); + } + + /** + * @since 2.7 + */ + public static Annotation[] findClassAnnotations(Class<?> cls) { + return _getMetadata(cls).getDeclaredAnnotations(); } /** * @since 2.7 */ - public static Constructor<?>[] findConstructors(Class<?> cls) + public static Constructor<?>[] findConstructors(Class<?> cls) { + return _getMetadata(cls).getConstructors(); + } + + private static Class<?>[] _interfaces(Class<?> cls) { + return _getMetadata(cls).getInterfaces(); + } + + private static ClassMetadata _getMetadata(Class<?> cls) { - Constructor<?>[] result = sConstructors.get(cls); - if (result == null) { - // Note: can NOT skip abstract classes as they may be used with mix-ins - // and for regular use shouldn't really matter. - if (cls.isInterface()) { - result = NO_CTORS; - } else { - result = cls.getDeclaredConstructors(); + ClassMetadata md = sCached.get(cls); + if (md == null) { + md = new ClassMetadata(cls); + // tiny optimization, but in case someone concurrently constructed it, + // let's use that instance, to reduce extra concurrent work. + ClassMetadata old = sCached.putIfAbsent(cls, md); + if (old != null) { + md = old; } - sConstructors.putIfAbsent(cls, result); } - return result; - } - - private static Class<?>[] _interfaces(Class<?> src) { - Class<?>[] result = sInterfaces.get(src); - if (result == null) { - result = src.getInterfaces(); - sInterfaces.putIfAbsent(src, result); - } - return result; + return md; } /* @@ -675,8 +691,8 @@ public final class ClassUtil } public static boolean isNonStaticInnerClass(Class<?> cls) { - return (cls.getEnclosingClass() != null) - && !Modifier.isStatic(cls.getModifiers()); + return !Modifier.isStatic(cls.getModifiers()) + && hasEnclosingClass(cls); } /* @@ -759,4 +775,122 @@ public final class ClassUtil return found; } } + + /* + /********************************************************** + /* Helper class for caching + /********************************************************** + */ + + /** + * @since 2.7 + */ + private final static class ClassMetadata + { + private final Class<?> _forClass; + + private Class<?> _enclosingClass; + private Boolean _hasEnclosingMethod; + private String _packageName; + + private Class<?>[] _interfaces; + private Annotation[] _annotations; + private Constructor<?>[] _constructors; + + private final boolean _isInterface; + + public ClassMetadata(Class<?> forClass) { + _forClass = forClass; + _isInterface = forClass.isInterface(); + } + + /* + public Class<?> getSuperclass() { + return _isInterface ? null : _forClass.getSuperclass(); + } + + public boolean isInteface() { + return _isInterface; + } + */ + + public String getPackageName() { + String name = _packageName; + if (name == null) { + Package pkg = _forClass.getPackage(); + name = (pkg == null) ? null : pkg.getName(); + if (name == null) { + name = ""; + } + _packageName = name; + } + return (name == "") ? null : name; + } + + public Class<?> getEnclosingClass() { + Class<?> enc = _enclosingClass; + if (enc == null) { + enc = _forClass.getEnclosingClass(); + if (enc == null) { + // Need marker to indicate "none", so: + enc = _forClass; + } + _enclosingClass = enc; + } + if (enc == _forClass) { + return null; + } + return enc; + } + + public boolean hasEnclosingMethod() { + Boolean b = _hasEnclosingMethod; + if (b == null) { + b = _forClass.getEnclosingMethod() != null; + _hasEnclosingMethod = b; + } + return b.booleanValue(); + } + + public Class<?>[] getInterfaces() { + // 19-Sep-2015, tatu: Bit of performance improvement, after finding this + // in profile; maybe 5% in "wasteful" deserialization case + + Class<?>[] result = _interfaces; + if (result == null) { + result = _forClass.getInterfaces(); + _interfaces = result; + } + return result; + } + + public Annotation[] getDeclaredAnnotations() { + // 19-Sep-2015, tatu: Modest performance improvement, after finding this + // in profile; maybe 2-3% in "wasteful" deserialization case + + Annotation[] result = _annotations; + if (result == null) { + result = _forClass.getDeclaredAnnotations(); + _annotations = result; + } + return result; + } + + public Constructor<?>[] getConstructors() { + // 19-Sep-2015, tatu: Some performance improvement, after finding this + // in profile; maybe 8-10% in "wasteful" deserialization case + Constructor<?>[] result = _constructors; + if (result == null) { + // Note: can NOT skip abstract classes as they may be used with mix-ins + // and for regular use shouldn't really matter. + if (_isInterface) { + result = NO_CTORS; + } else { + result = _forClass.getDeclaredConstructors(); + } + _constructors = result; + } + return result; + } + } } |