aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTatu Saloranta <tatu.saloranta@iki.fi>2015-09-21 09:52:45 -0700
committerTatu Saloranta <tatu.saloranta@iki.fi>2015-09-21 09:52:45 -0700
commitd6699257b2f60fd10251862870d73743f785acea (patch)
treec5d6399e630d1f7e1961c88fa09c35a92c9a6f37
parentcbb008c94f4ab236e83bfe01220e6de3fa509e07 (diff)
downloadjackson-databind-d6699257b2f60fd10251862870d73743f785acea.tar.gz
streamlining earlier perf improvements
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/JsonMappingException.java7
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/introspect/BasicClassIntrospector.java6
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/type/TypeBindings.java10
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/util/BeanUtil.java21
-rw-r--r--src/main/java/com/fasterxml/jackson/databind/util/ClassUtil.java212
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;
+ }
+ }
}