@@ -14,6 +14,9 @@ public final class ClassUtil
14
14
{
15
15
private final static Class <?> CLS_OBJECT = Object .class ;
16
16
17
+ private final static Annotation [] NO_ANNOTATIONS = new Annotation [0 ];
18
+ private final static Ctor [] NO_CTORS = new Ctor [0 ];
19
+
17
20
/*
18
21
/**********************************************************
19
22
/* Helper classes
@@ -905,57 +908,68 @@ public static boolean isObjectOrPrimitive(Class<?> cls) {
905
908
906
909
/*
907
910
/**********************************************************
908
- /* Caching access to class metadata, added in 2.7
911
+ /* Access to various Class definition aspects; possibly
912
+ /* cacheable; and attempts was made in 2.7.0 - 2.7.7; however
913
+ /* unintented retention (~= memory leak) wrt [databind#1363]
914
+ /* resulted in removal of caching
909
915
/**********************************************************
910
916
*/
911
917
912
- /* 17-Sep-2015, tatu: Although access methods should not be significant
913
- * problems for most proper usage, they may become problematic if
914
- * ObjectMapper has to be re-created; and especially so on Android.
915
- * So let's do somewhat aggressive caching.
916
- */
917
- private final static LRUMap <Class <?>,ClassMetadata > sCached = new LRUMap <Class <?>,ClassMetadata >(48 , 48 );
918
-
919
918
/**
920
919
* @since 2.7
921
920
*/
922
921
public static String getPackageName (Class <?> cls ) {
923
- return _getMetadata (cls ).getPackageName ();
922
+ Package pkg = cls .getPackage ();
923
+ return (pkg == null ) ? null : pkg .getName ();
924
924
}
925
925
926
926
/**
927
927
* @since 2.7
928
928
*/
929
929
public static boolean hasEnclosingMethod (Class <?> cls ) {
930
- return _getMetadata (cls ). hasEnclosingMethod ( );
930
+ return ! isObjectOrPrimitive (cls ) && ( cls . getEnclosingMethod () != null );
931
931
}
932
932
933
933
/**
934
934
* @since 2.7
935
935
*/
936
936
public static Field [] getDeclaredFields (Class <?> cls ) {
937
- return _getMetadata ( cls ) .getDeclaredFields ();
937
+ return cls .getDeclaredFields ();
938
938
}
939
939
940
940
/**
941
941
* @since 2.7
942
942
*/
943
943
public static Method [] getDeclaredMethods (Class <?> cls ) {
944
- return _getMetadata ( cls ) .getDeclaredMethods ();
944
+ return cls .getDeclaredMethods ();
945
945
}
946
946
947
947
/**
948
948
* @since 2.7
949
949
*/
950
950
public static Annotation [] findClassAnnotations (Class <?> cls ) {
951
- return _getMetadata (cls ).getDeclaredAnnotations ();
951
+ if (isObjectOrPrimitive (cls )) {
952
+ return NO_ANNOTATIONS ;
953
+ }
954
+ return cls .getDeclaredAnnotations ();
952
955
}
953
956
954
957
/**
955
958
* @since 2.7
956
959
*/
957
960
public static Ctor [] getConstructors (Class <?> cls ) {
958
- return _getMetadata (cls ).getConstructors ();
961
+ // Note: can NOT skip abstract classes as they may be used with mix-ins
962
+ // and for regular use shouldn't really matter.
963
+ if (cls .isInterface () || isObjectOrPrimitive (cls )) {
964
+ return NO_CTORS ;
965
+ }
966
+ Constructor <?>[] rawCtors = cls .getDeclaredConstructors ();
967
+ final int len = rawCtors .length ;
968
+ Ctor [] result = new Ctor [len ];
969
+ for (int i = 0 ; i < len ; ++i ) {
970
+ result [i ] = new Ctor (rawCtors [i ]);
971
+ }
972
+ return result ;
959
973
}
960
974
961
975
// // // Then methods that do NOT cache access but were considered
@@ -980,7 +994,7 @@ public static Type getGenericSuperclass(Class<?> cls) {
980
994
* @since 2.7
981
995
*/
982
996
public static Type [] getGenericInterfaces (Class <?> cls ) {
983
- return _getMetadata ( cls ) .getGenericInterfaces ();
997
+ return cls .getGenericInterfaces ();
984
998
}
985
999
986
1000
/**
@@ -992,22 +1006,7 @@ public static Class<?> getEnclosingClass(Class<?> cls) {
992
1006
}
993
1007
994
1008
private static Class <?>[] _interfaces (Class <?> cls ) {
995
- return _getMetadata (cls ).getInterfaces ();
996
- }
997
-
998
- private static ClassMetadata _getMetadata (Class <?> cls )
999
- {
1000
- ClassMetadata md = sCached .get (cls );
1001
- if (md == null ) {
1002
- md = new ClassMetadata (cls );
1003
- // tiny optimization, but in case someone concurrently constructed it,
1004
- // let's use that instance, to reduce extra concurrent work.
1005
- ClassMetadata old = sCached .putIfAbsent (cls , md );
1006
- if (old != null ) {
1007
- md = old ;
1008
- }
1009
- }
1010
- return md ;
1009
+ return cls .getInterfaces ();
1011
1010
}
1012
1011
1013
1012
/*
@@ -1097,144 +1096,6 @@ private static Field locateField(Class<?> fromClass, String expectedName, Class<
1097
1096
/**********************************************************
1098
1097
*/
1099
1098
1100
- /**
1101
- * @since 2.7
1102
- */
1103
- private final static class ClassMetadata
1104
- {
1105
- private final static Annotation [] NO_ANNOTATIONS = new Annotation [0 ];
1106
- private final static Ctor [] NO_CTORS = new Ctor [0 ];
1107
-
1108
- private final Class <?> _forClass ;
1109
-
1110
- private String _packageName ;
1111
- private Boolean _hasEnclosingMethod ;
1112
-
1113
- private Class <?>[] _interfaces ;
1114
- private Type [] _genericInterfaces ;
1115
-
1116
- private Annotation [] _annotations ;
1117
- private Ctor [] _constructors ;
1118
- private Field [] _fields ;
1119
- private Method [] _methods ;
1120
-
1121
- public ClassMetadata (Class <?> forClass ) {
1122
- _forClass = forClass ;
1123
- }
1124
-
1125
- public String getPackageName () {
1126
- String name = _packageName ;
1127
- if (name == null ) {
1128
- Package pkg = _forClass .getPackage ();
1129
- name = (pkg == null ) ? null : pkg .getName ();
1130
- if (name == null ) {
1131
- name = "" ;
1132
- }
1133
- _packageName = name ;
1134
- }
1135
- return (name == "" ) ? null : name ;
1136
- }
1137
-
1138
- // 19-Sep-2015, tatu: Bit of performance improvement, after finding this
1139
- // in profile; maybe 5% in "wasteful" deserialization case
1140
- public Class <?>[] getInterfaces () {
1141
- Class <?>[] result = _interfaces ;
1142
- if (result == null ) {
1143
- result = _forClass .getInterfaces ();
1144
- _interfaces = result ;
1145
- }
1146
- return result ;
1147
- }
1148
-
1149
- // 30-Oct-2015, tatu: Minor performance boost too (5% or less)
1150
- public Type [] getGenericInterfaces () {
1151
- Type [] result = _genericInterfaces ;
1152
- if (result == null ) {
1153
- result = _forClass .getGenericInterfaces ();
1154
- _genericInterfaces = result ;
1155
- }
1156
- return result ;
1157
- }
1158
-
1159
- // 19-Sep-2015, tatu: Modest performance improvement, after finding this
1160
- // in profile; maybe 2-3% in "wasteful" deserialization case
1161
- public Annotation [] getDeclaredAnnotations () {
1162
- Annotation [] result = _annotations ;
1163
- if (result == null ) {
1164
- result = isObjectOrPrimitive () ? NO_ANNOTATIONS : _forClass .getDeclaredAnnotations ();
1165
- _annotations = result ;
1166
- }
1167
- return result ;
1168
- }
1169
-
1170
- // 19-Sep-2015, tatu: Some performance improvement, after finding this
1171
- // in profile; maybe 8-10% in "wasteful" deserialization case
1172
- public Ctor [] getConstructors () {
1173
- Ctor [] result = _constructors ;
1174
- if (result == null ) {
1175
- // Note: can NOT skip abstract classes as they may be used with mix-ins
1176
- // and for regular use shouldn't really matter.
1177
- if (_forClass .isInterface () || isObjectOrPrimitive ()) {
1178
- result = NO_CTORS ;
1179
- } else {
1180
- Constructor <?>[] rawCtors = _forClass .getDeclaredConstructors ();
1181
- final int len = rawCtors .length ;
1182
- result = new Ctor [len ];
1183
- for (int i = 0 ; i < len ; ++i ) {
1184
- result [i ] = new Ctor (rawCtors [i ]);
1185
- }
1186
- }
1187
- _constructors = result ;
1188
- }
1189
- return result ;
1190
- }
1191
-
1192
- // 21-Spe-2015, tatu: Surprisingly significant improvement (+10%)...
1193
- public Field [] getDeclaredFields () {
1194
- Field [] fields = _fields ;
1195
- if (fields == null ) {
1196
- fields = _forClass .getDeclaredFields ();
1197
- _fields = fields ;
1198
- }
1199
- return fields ;
1200
- }
1201
-
1202
- // 21-Spe-2015, tatu: Surprisingly significant improvement (+30%)...
1203
- public Method [] getDeclaredMethods () {
1204
- Method [] methods = _methods ;
1205
- if (methods == null ) {
1206
- methods = _forClass .getDeclaredMethods ();
1207
- _methods = methods ;
1208
- }
1209
- return methods ;
1210
- }
1211
-
1212
- // Prominently listed on profiling when not cached, improvement
1213
- // modest, 1-2% range; but at least is measurable so keep it
1214
- public boolean hasEnclosingMethod () {
1215
- Boolean b = _hasEnclosingMethod ;
1216
- if (b == null ) {
1217
- b = isObjectOrPrimitive () ? Boolean .FALSE : Boolean .valueOf (_forClass .getEnclosingMethod () != null );
1218
- _hasEnclosingMethod = b ;
1219
- }
1220
- return b .booleanValue ();
1221
- }
1222
-
1223
- private boolean isObjectOrPrimitive () {
1224
- return (_forClass == CLS_OBJECT ) || _forClass .isPrimitive ();
1225
- }
1226
-
1227
- /* And then we have a bunch of accessors that did show up in profiling
1228
- * of "wasteful" cases, but for which caching did not yield non-trivial
1229
- * improvements (for tests less than 1% improvement)
1230
- */
1231
-
1232
- // Caching does not seem worthwhile, as per profiling
1233
- // public Type getGenericSuperclass();
1234
- // public Class<?> getDeclaringClass();
1235
- // public Class<?> getEnclosingClass();
1236
- }
1237
-
1238
1099
/**
1239
1100
* Value class used for caching Constructor declarations; used because
1240
1101
* caching done by JDK appears to be somewhat inefficient for some use cases.
0 commit comments