@@ -11,6 +11,9 @@ public final class ClassUtil
11
11
{
12
12
private final static Class <?> CLS_OBJECT = Object .class ;
13
13
14
+ private final static Annotation [] NO_ANNOTATIONS = new Annotation [0 ];
15
+ private final static Ctor [] NO_CTORS = new Ctor [0 ];
16
+
14
17
/*
15
18
/**********************************************************
16
19
/* Helper classes
@@ -790,57 +793,68 @@ public static boolean isObjectOrPrimitive(Class<?> cls) {
790
793
791
794
/*
792
795
/**********************************************************
793
- /* Caching access to class metadata, added in 2.7
796
+ /* Access to various Class definition aspects; possibly
797
+ /* cacheable; and attempts was made in 2.7.0 - 2.7.7; however
798
+ /* unintented retention (~= memory leak) wrt [databind#1363]
799
+ /* resulted in removal of caching
794
800
/**********************************************************
795
801
*/
796
802
797
- /* 17-Sep-2015, tatu: Although access methods should not be significant
798
- * problems for most proper usage, they may become problematic if
799
- * ObjectMapper has to be re-created; and especially so on Android.
800
- * So let's do somewhat aggressive caching.
801
- */
802
- private final static LRUMap <Class <?>,ClassMetadata > sCached = new LRUMap <Class <?>,ClassMetadata >(48 , 48 );
803
-
804
803
/**
805
804
* @since 2.7
806
805
*/
807
806
public static String getPackageName (Class <?> cls ) {
808
- return _getMetadata (cls ).getPackageName ();
807
+ Package pkg = cls .getPackage ();
808
+ return (pkg == null ) ? null : pkg .getName ();
809
809
}
810
810
811
811
/**
812
812
* @since 2.7
813
813
*/
814
814
public static boolean hasEnclosingMethod (Class <?> cls ) {
815
- return _getMetadata (cls ). hasEnclosingMethod ( );
815
+ return ! isObjectOrPrimitive (cls ) && ( cls . getEnclosingMethod () != null );
816
816
}
817
817
818
818
/**
819
819
* @since 2.7
820
820
*/
821
821
public static Field [] getDeclaredFields (Class <?> cls ) {
822
- return _getMetadata ( cls ) .getDeclaredFields ();
822
+ return cls .getDeclaredFields ();
823
823
}
824
824
825
825
/**
826
826
* @since 2.7
827
827
*/
828
828
public static Method [] getDeclaredMethods (Class <?> cls ) {
829
- return _getMetadata ( cls ) .getDeclaredMethods ();
829
+ return cls .getDeclaredMethods ();
830
830
}
831
831
832
832
/**
833
833
* @since 2.7
834
834
*/
835
835
public static Annotation [] findClassAnnotations (Class <?> cls ) {
836
- return _getMetadata (cls ).getDeclaredAnnotations ();
836
+ if (isObjectOrPrimitive (cls )) {
837
+ return NO_ANNOTATIONS ;
838
+ }
839
+ return cls .getDeclaredAnnotations ();
837
840
}
838
841
839
842
/**
840
843
* @since 2.7
841
844
*/
842
845
public static Ctor [] getConstructors (Class <?> cls ) {
843
- return _getMetadata (cls ).getConstructors ();
846
+ // Note: can NOT skip abstract classes as they may be used with mix-ins
847
+ // and for regular use shouldn't really matter.
848
+ if (cls .isInterface () || isObjectOrPrimitive (cls )) {
849
+ return NO_CTORS ;
850
+ }
851
+ Constructor <?>[] rawCtors = cls .getDeclaredConstructors ();
852
+ final int len = rawCtors .length ;
853
+ Ctor [] result = new Ctor [len ];
854
+ for (int i = 0 ; i < len ; ++i ) {
855
+ result [i ] = new Ctor (rawCtors [i ]);
856
+ }
857
+ return result ;
844
858
}
845
859
846
860
// // // Then methods that do NOT cache access but were considered
@@ -865,7 +879,7 @@ public static Type getGenericSuperclass(Class<?> cls) {
865
879
* @since 2.7
866
880
*/
867
881
public static Type [] getGenericInterfaces (Class <?> cls ) {
868
- return _getMetadata ( cls ) .getGenericInterfaces ();
882
+ return cls .getGenericInterfaces ();
869
883
}
870
884
871
885
/**
@@ -877,22 +891,7 @@ public static Class<?> getEnclosingClass(Class<?> cls) {
877
891
}
878
892
879
893
private static Class <?>[] _interfaces (Class <?> cls ) {
880
- return _getMetadata (cls ).getInterfaces ();
881
- }
882
-
883
- private static ClassMetadata _getMetadata (Class <?> cls )
884
- {
885
- ClassMetadata md = sCached .get (cls );
886
- if (md == null ) {
887
- md = new ClassMetadata (cls );
888
- // tiny optimization, but in case someone concurrently constructed it,
889
- // let's use that instance, to reduce extra concurrent work.
890
- ClassMetadata old = sCached .putIfAbsent (cls , md );
891
- if (old != null ) {
892
- md = old ;
893
- }
894
- }
895
- return md ;
894
+ return cls .getInterfaces ();
896
895
}
897
896
898
897
/*
@@ -982,144 +981,6 @@ private static Field locateField(Class<?> fromClass, String expectedName, Class<
982
981
/**********************************************************
983
982
*/
984
983
985
- /**
986
- * @since 2.7
987
- */
988
- private final static class ClassMetadata
989
- {
990
- private final static Annotation [] NO_ANNOTATIONS = new Annotation [0 ];
991
- private final static Ctor [] NO_CTORS = new Ctor [0 ];
992
-
993
- private final Class <?> _forClass ;
994
-
995
- private String _packageName ;
996
- private Boolean _hasEnclosingMethod ;
997
-
998
- private Class <?>[] _interfaces ;
999
- private Type [] _genericInterfaces ;
1000
-
1001
- private Annotation [] _annotations ;
1002
- private Ctor [] _constructors ;
1003
- private Field [] _fields ;
1004
- private Method [] _methods ;
1005
-
1006
- public ClassMetadata (Class <?> forClass ) {
1007
- _forClass = forClass ;
1008
- }
1009
-
1010
- public String getPackageName () {
1011
- String name = _packageName ;
1012
- if (name == null ) {
1013
- Package pkg = _forClass .getPackage ();
1014
- name = (pkg == null ) ? null : pkg .getName ();
1015
- if (name == null ) {
1016
- name = "" ;
1017
- }
1018
- _packageName = name ;
1019
- }
1020
- return (name == "" ) ? null : name ;
1021
- }
1022
-
1023
- // 19-Sep-2015, tatu: Bit of performance improvement, after finding this
1024
- // in profile; maybe 5% in "wasteful" deserialization case
1025
- public Class <?>[] getInterfaces () {
1026
- Class <?>[] result = _interfaces ;
1027
- if (result == null ) {
1028
- result = _forClass .getInterfaces ();
1029
- _interfaces = result ;
1030
- }
1031
- return result ;
1032
- }
1033
-
1034
- // 30-Oct-2015, tatu: Minor performance boost too (5% or less)
1035
- public Type [] getGenericInterfaces () {
1036
- Type [] result = _genericInterfaces ;
1037
- if (result == null ) {
1038
- result = _forClass .getGenericInterfaces ();
1039
- _genericInterfaces = result ;
1040
- }
1041
- return result ;
1042
- }
1043
-
1044
- // 19-Sep-2015, tatu: Modest performance improvement, after finding this
1045
- // in profile; maybe 2-3% in "wasteful" deserialization case
1046
- public Annotation [] getDeclaredAnnotations () {
1047
- Annotation [] result = _annotations ;
1048
- if (result == null ) {
1049
- result = isObjectOrPrimitive () ? NO_ANNOTATIONS : _forClass .getDeclaredAnnotations ();
1050
- _annotations = result ;
1051
- }
1052
- return result ;
1053
- }
1054
-
1055
- // 19-Sep-2015, tatu: Some performance improvement, after finding this
1056
- // in profile; maybe 8-10% in "wasteful" deserialization case
1057
- public Ctor [] getConstructors () {
1058
- Ctor [] result = _constructors ;
1059
- if (result == null ) {
1060
- // Note: can NOT skip abstract classes as they may be used with mix-ins
1061
- // and for regular use shouldn't really matter.
1062
- if (_forClass .isInterface () || isObjectOrPrimitive ()) {
1063
- result = NO_CTORS ;
1064
- } else {
1065
- Constructor <?>[] rawCtors = _forClass .getDeclaredConstructors ();
1066
- final int len = rawCtors .length ;
1067
- result = new Ctor [len ];
1068
- for (int i = 0 ; i < len ; ++i ) {
1069
- result [i ] = new Ctor (rawCtors [i ]);
1070
- }
1071
- }
1072
- _constructors = result ;
1073
- }
1074
- return result ;
1075
- }
1076
-
1077
- // 21-Spe-2015, tatu: Surprisingly significant improvement (+10%)...
1078
- public Field [] getDeclaredFields () {
1079
- Field [] fields = _fields ;
1080
- if (fields == null ) {
1081
- fields = _forClass .getDeclaredFields ();
1082
- _fields = fields ;
1083
- }
1084
- return fields ;
1085
- }
1086
-
1087
- // 21-Spe-2015, tatu: Surprisingly significant improvement (+30%)...
1088
- public Method [] getDeclaredMethods () {
1089
- Method [] methods = _methods ;
1090
- if (methods == null ) {
1091
- methods = _forClass .getDeclaredMethods ();
1092
- _methods = methods ;
1093
- }
1094
- return methods ;
1095
- }
1096
-
1097
- // Prominently listed on profiling when not cached, improvement
1098
- // modest, 1-2% range; but at least is measurable so keep it
1099
- public boolean hasEnclosingMethod () {
1100
- Boolean b = _hasEnclosingMethod ;
1101
- if (b == null ) {
1102
- b = isObjectOrPrimitive () ? Boolean .FALSE : Boolean .valueOf (_forClass .getEnclosingMethod () != null );
1103
- _hasEnclosingMethod = b ;
1104
- }
1105
- return b .booleanValue ();
1106
- }
1107
-
1108
- private boolean isObjectOrPrimitive () {
1109
- return (_forClass == CLS_OBJECT ) || _forClass .isPrimitive ();
1110
- }
1111
-
1112
- /* And then we have a bunch of accessors that did show up in profiling
1113
- * of "wasteful" cases, but for which caching did not yield non-trivial
1114
- * improvements (for tests less than 1% improvement)
1115
- */
1116
-
1117
- // Caching does not seem worthwhile, as per profiling
1118
- // public Type getGenericSuperclass();
1119
- // public Class<?> getDeclaringClass();
1120
- // public Class<?> getEnclosingClass();
1121
- }
1122
-
1123
984
/**
1124
985
* Value class used for caching Constructor declarations; used because
1125
986
* caching done by JDK appears to be somewhat inefficient for some use cases.
0 commit comments