11package com .fasterxml .jackson .databind .introspect ;
22
3+ import java .util .Collection ;
4+ import java .util .Map ;
5+
36import com .fasterxml .jackson .databind .AnnotationIntrospector ;
47import com .fasterxml .jackson .databind .DeserializationConfig ;
58import com .fasterxml .jackson .databind .JavaType ;
69import com .fasterxml .jackson .databind .SerializationConfig ;
710import com .fasterxml .jackson .databind .annotation .JsonPOJOBuilder ;
811import com .fasterxml .jackson .databind .cfg .MapperConfig ;
912import com .fasterxml .jackson .databind .type .SimpleType ;
13+ import com .fasterxml .jackson .databind .util .LRUMap ;
1014
1115public class BasicClassIntrospector
1216 extends ClassIntrospector
@@ -19,6 +23,8 @@ public class BasicClassIntrospector
1923 * This is strictly performance optimization to reduce what is
2024 * usually one-time cost, but seems useful for some cases considering
2125 * simplicity.
26+ *
27+ * @since 2.4
2228 */
2329
2430 protected final static BasicBeanDescription STRING_DESC ;
@@ -48,9 +54,21 @@ public class BasicClassIntrospector
4854 /**********************************************************
4955 */
5056
57+ @ Deprecated // since 2.5: construct instance directly
5158 public final static BasicClassIntrospector instance = new BasicClassIntrospector ();
5259
53- public BasicClassIntrospector () { }
60+ /**
61+ * Looks like 'forClassAnnotations()' gets called so frequently that we
62+ * should consider caching to avoid some of the lookups.
63+ *
64+ * @since 2.5
65+ */
66+ protected final LRUMap <JavaType ,BasicBeanDescription > _cachedFCA ;
67+
68+ public BasicClassIntrospector () {
69+ // a small cache should go a long way here
70+ _cachedFCA = new LRUMap <JavaType ,BasicBeanDescription >(16 , 64 );
71+ }
5472
5573 /*
5674 /**********************************************************
@@ -62,11 +80,18 @@ public BasicClassIntrospector() { }
6280 public BasicBeanDescription forSerialization (SerializationConfig cfg ,
6381 JavaType type , MixInResolver r )
6482 {
65- // minor optimization: for JDK types do minimal introspection
66- BasicBeanDescription desc = _findCachedDesc (type );
83+ // minor optimization: for some JDK types do minimal introspection
84+ BasicBeanDescription desc = _findStdTypeDesc (type );
6785 if (desc == null ) {
68- desc = BasicBeanDescription .forSerialization (collectProperties (cfg ,
69- type , r , true , "set" ));
86+ // As per [Databind#550], skip full introspection for some of standard
87+ // structured types as well
88+ desc = _findStdJdkCollectionDesc (cfg , type , r );
89+ if (desc == null ) {
90+ desc = BasicBeanDescription .forSerialization (collectProperties (cfg ,
91+ type , r , true , "set" ));
92+ }
93+ // Also: this is a superset of "forClassAnnotations", so may optimize by optional add:
94+ _cachedFCA .putIfAbsent (type , desc );
7095 }
7196 return desc ;
7297 }
@@ -75,11 +100,18 @@ public BasicBeanDescription forSerialization(SerializationConfig cfg,
75100 public BasicBeanDescription forDeserialization (DeserializationConfig cfg ,
76101 JavaType type , MixInResolver r )
77102 {
78- // minor optimization: for JDK types do minimal introspection
79- BasicBeanDescription desc = _findCachedDesc (type );
103+ // minor optimization: for some JDK types do minimal introspection
104+ BasicBeanDescription desc = _findStdTypeDesc (type );
80105 if (desc == null ) {
81- desc = BasicBeanDescription .forDeserialization (collectProperties (cfg ,
82- type , r , false , "set" ));
106+ // As per [Databind#550], skip full introspection for some of standard
107+ // structured types as well
108+ desc = _findStdJdkCollectionDesc (cfg , type , r );
109+ if (desc == null ) {
110+ desc = BasicBeanDescription .forDeserialization (collectProperties (cfg ,
111+ type , r , false , "set" ));
112+ }
113+ // Also: this is a superset of "forClassAnnotations", so may optimize by optional add:
114+ _cachedFCA .putIfAbsent (type , desc );
83115 }
84116 return desc ;
85117 }
@@ -88,42 +120,65 @@ public BasicBeanDescription forDeserialization(DeserializationConfig cfg,
88120 public BasicBeanDescription forDeserializationWithBuilder (DeserializationConfig cfg ,
89121 JavaType type , MixInResolver r )
90122 {
91- // no caching for Builders (no standard JDK builder types):
92- return BasicBeanDescription .forDeserialization (collectPropertiesWithBuilder (cfg ,
93- type , r , false ));
123+ // no std JDK types with Builders, so:
124+
125+ BasicBeanDescription desc = BasicBeanDescription .forDeserialization (collectPropertiesWithBuilder (cfg ,
126+ type , r , false ));
127+ // this is still a superset of "forClassAnnotations", so may optimize by optional add:
128+ _cachedFCA .putIfAbsent (type , desc );
129+ return desc ;
94130 }
95131
96132 @ Override
97133 public BasicBeanDescription forCreation (DeserializationConfig cfg ,
98134 JavaType type , MixInResolver r )
99135 {
100- BasicBeanDescription desc = _findCachedDesc (type );
136+ BasicBeanDescription desc = _findStdTypeDesc (type );
101137 if (desc == null ) {
102- desc = BasicBeanDescription .forDeserialization (
138+
139+ // As per [Databind#550], skip full introspection for some of standard
140+ // structured types as well
141+ desc = _findStdJdkCollectionDesc (cfg , type , r );
142+ if (desc == null ) {
143+ desc = BasicBeanDescription .forDeserialization (
103144 collectProperties (cfg , type , r , false , "set" ));
145+ }
104146 }
147+ // should this be cached for FCA?
105148 return desc ;
106149 }
107150
108151 @ Override
109152 public BasicBeanDescription forClassAnnotations (MapperConfig <?> cfg ,
110153 JavaType type , MixInResolver r )
111154 {
112- boolean useAnnotations = cfg .isAnnotationProcessingEnabled ();
113- AnnotatedClass ac = AnnotatedClass .construct (type .getRawClass (),
114- (useAnnotations ? cfg .getAnnotationIntrospector () : null ), r );
115- return BasicBeanDescription .forOtherUse (cfg , type , ac );
155+ BasicBeanDescription desc = _findStdTypeDesc (type );
156+ if (desc == null ) {
157+ desc = _cachedFCA .get (type );
158+ if (desc == null ) {
159+ boolean useAnnotations = cfg .isAnnotationProcessingEnabled ();
160+ AnnotatedClass ac = AnnotatedClass .construct (type .getRawClass (),
161+ (useAnnotations ? cfg .getAnnotationIntrospector () : null ), r );
162+ desc = BasicBeanDescription .forOtherUse (cfg , type , ac );
163+ _cachedFCA .put (type , desc );
164+ }
165+ }
166+ return desc ;
116167 }
117168
118169 @ Override
119170 public BasicBeanDescription forDirectClassAnnotations (MapperConfig <?> cfg ,
120171 JavaType type , MixInResolver r )
121172 {
122- boolean useAnnotations = cfg .isAnnotationProcessingEnabled ();
123- AnnotationIntrospector ai = cfg .getAnnotationIntrospector ();
124- AnnotatedClass ac = AnnotatedClass .constructWithoutSuperTypes (type .getRawClass (),
125- (useAnnotations ? ai : null ), r );
126- return BasicBeanDescription .forOtherUse (cfg , type , ac );
173+ BasicBeanDescription desc = _findStdTypeDesc (type );
174+ if (desc == null ) {
175+ boolean useAnnotations = cfg .isAnnotationProcessingEnabled ();
176+ AnnotationIntrospector ai = cfg .getAnnotationIntrospector ();
177+ AnnotatedClass ac = AnnotatedClass .constructWithoutSuperTypes (type .getRawClass (),
178+ (useAnnotations ? ai : null ), r );
179+ desc = BasicBeanDescription .forOtherUse (cfg , type , ac );
180+ }
181+ return desc ;
127182 }
128183
129184 /*
@@ -167,20 +222,62 @@ protected POJOPropertiesCollector constructPropertyCollector(MapperConfig<?> con
167222 * Method called to see if type is one of core JDK types
168223 * that we have cached for efficiency.
169224 */
170- protected BasicBeanDescription _findCachedDesc (JavaType type )
225+ protected BasicBeanDescription _findStdTypeDesc (JavaType type )
171226 {
172227 Class <?> cls = type .getRawClass ();
173- if (cls == String .class ) {
174- return STRING_DESC ;
228+ if (cls .isPrimitive ()) {
229+ if (cls == Boolean .TYPE ) {
230+ return BOOLEAN_DESC ;
231+ }
232+ if (cls == Integer .TYPE ) {
233+ return INT_DESC ;
234+ }
235+ if (cls == Long .TYPE ) {
236+ return LONG_DESC ;
237+ }
238+ } else {
239+ if (cls == String .class ) {
240+ return STRING_DESC ;
241+ }
175242 }
176- if (cls == Boolean .TYPE ) {
177- return BOOLEAN_DESC ;
243+ return null ;
244+ }
245+
246+ /**
247+ * Helper method used to decide whether we can omit introspection
248+ * for members (methods, fields, constructors); we may do so for
249+ * a limited number of container types JDK provides.
250+ */
251+ protected boolean _isStdJDKCollection (JavaType type )
252+ {
253+ if (!type .isContainerType () || type .isArrayType ()) {
254+ return false ;
178255 }
179- if (cls == Integer .TYPE ) {
180- return INT_DESC ;
256+ Class <?> raw = type .getRawClass ();
257+ Package pkg = raw .getPackage ();
258+ if (pkg != null ) {
259+ String pkgName = pkg .getName ();
260+ if (pkgName .startsWith ("java.lang" )
261+ || pkgName .startsWith ("java.util" )) {
262+ /* 23-Sep-2014, tatu: Should we be conservative here (minimal number
263+ * of matches), or ambitious? Let's do latter for now.
264+ */
265+ if (Collection .class .isAssignableFrom (raw )
266+ || Map .class .isAssignableFrom (raw )) {
267+ return true ;
268+ }
269+ }
181270 }
182- if (cls == Long .TYPE ) {
183- return LONG_DESC ;
271+ return false ;
272+ }
273+
274+ protected BasicBeanDescription _findStdJdkCollectionDesc (MapperConfig <?> cfg ,
275+ JavaType type , MixInResolver r )
276+ {
277+ if (_isStdJDKCollection (type )) {
278+ AnnotatedClass ac = AnnotatedClass .construct (type .getRawClass (),
279+ (cfg .isAnnotationProcessingEnabled () ? cfg .getAnnotationIntrospector () : null ), r );
280+ return BasicBeanDescription .forOtherUse (cfg , type , ac );
184281 }
185282 return null ;
186283 }
0 commit comments