1 package com.fasterxml.jackson.databind.introspect;
2
3 import java.util.Collection;
4 import java.util.Map;
5
6 import com.fasterxml.jackson.databind.AnnotationIntrospector;
7 import com.fasterxml.jackson.databind.DeserializationConfig;
8 import com.fasterxml.jackson.databind.JavaType;
9 import com.fasterxml.jackson.databind.JsonNode;
10 import com.fasterxml.jackson.databind.SerializationConfig;
11 import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
12 import com.fasterxml.jackson.databind.cfg.MapperConfig;
13 import com.fasterxml.jackson.databind.type.SimpleType;
14 import com.fasterxml.jackson.databind.util.ClassUtil;
15
16 public class BasicClassIntrospector
17     extends ClassIntrospector
18     implements java.io.Serializable
19 {
20     private static final long serialVersionUID = 2L;
21
22     private final static Class<?> CLS_OBJECT = Object.class;
23     private final static Class<?> CLS_STRING = String.class;
24     private final static Class<?> CLS_JSON_NODE = JsonNode.class;
25
26     /* We keep a small set of pre-constructed descriptions to use for
27      * common non-structured values, such as Numbers and Strings.
28      * This is strictly performance optimization to reduce what is
29      * usually one-time cost, but seems useful for some cases considering
30      * simplicity.
31      *
32      * @since 2.4
33      */

34     protected final static BasicBeanDescription STRING_DESC;
35     static {
36         STRING_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(String.class),
37                 AnnotatedClassResolver.createPrimordial(CLS_STRING));
38     }
39     protected final static BasicBeanDescription BOOLEAN_DESC;
40     static {
41         BOOLEAN_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Boolean.TYPE),
42                 AnnotatedClassResolver.createPrimordial(Boolean.TYPE));
43     }
44     protected final static BasicBeanDescription INT_DESC;
45     static {
46         INT_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Integer.TYPE),
47                 AnnotatedClassResolver.createPrimordial(Integer.TYPE));
48     }
49     protected final static BasicBeanDescription LONG_DESC;
50     static {
51         LONG_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Long.TYPE),
52                 AnnotatedClassResolver.createPrimordial(Long.TYPE));
53     }
54     protected final static BasicBeanDescription OBJECT_DESC;
55     static {
56         OBJECT_DESC = BasicBeanDescription.forOtherUse(null, SimpleType.constructUnsafe(Object.class),
57                 AnnotatedClassResolver.createPrimordial(CLS_OBJECT));
58     }
59
60     /*
61     /**********************************************************
62     /* Life cycle
63     /**********************************************************
64      */

65
66     public BasicClassIntrospector() {
67     }
68
69     @Override
70     public ClassIntrospector copy() {
71         return new BasicClassIntrospector();
72     }
73
74     /*
75     /**********************************************************
76     /* Factory method impls
77     /**********************************************************
78      */

79
80     @Override
81     public BasicBeanDescription forSerialization(SerializationConfig config,
82             JavaType type, MixInResolver r)
83     {
84         // minor optimization: for some JDK types do minimal introspection
85         BasicBeanDescription desc = _findStdTypeDesc(config, type);
86         if (desc == null) {
87             // As per [databind#550], skip full introspection for some of standard
88             // structured types as well
89             desc = _findStdJdkCollectionDesc(config, type);
90             if (desc == null) {
91                 desc = BasicBeanDescription.forSerialization(collectProperties(config,
92                         type, r, true"set"));
93             }
94         }
95         return desc;
96     }
97
98     @Override
99     public BasicBeanDescription forDeserialization(DeserializationConfig config,
100             JavaType type, MixInResolver r)
101     {
102         // minor optimization: for some JDK types do minimal introspection
103         BasicBeanDescription desc = _findStdTypeDesc(config, type);
104         if (desc == null) {
105             // As per [Databind#550], skip full introspection for some of standard
106             // structured types as well
107             desc = _findStdJdkCollectionDesc(config, type);
108             if (desc == null) {
109                 desc = BasicBeanDescription.forDeserialization(collectProperties(config,
110                                 type, r, false"set"));
111             }
112         }
113         return desc;
114     }
115
116     @Override
117     public BasicBeanDescription forDeserializationWithBuilder(DeserializationConfig config,
118             JavaType type, MixInResolver r)
119     {
120         // no std JDK types with Builders, so:
121         return BasicBeanDescription.forDeserialization(collectPropertiesWithBuilder(config,
122                 type, r, false));
123     }
124
125     @Override
126     public BasicBeanDescription forCreation(DeserializationConfig config,
127             JavaType type, MixInResolver r)
128     {
129         BasicBeanDescription desc = _findStdTypeDesc(config, type);
130         if (desc == null) {
131             // As per [databind#550], skip full introspection for some of standard
132             // structured types as well
133             desc = _findStdJdkCollectionDesc(config, type);
134             if (desc == null) {
135                 desc = BasicBeanDescription.forDeserialization(
136                         collectProperties(config, type, r, false"set"));
137             }
138         }
139         return desc;
140     }
141
142     @Override
143     public BasicBeanDescription forClassAnnotations(MapperConfig<?> config,
144             JavaType type, MixInResolver r)
145     {
146         BasicBeanDescription desc = _findStdTypeDesc(config, type);
147         if (desc == null) {
148             desc = BasicBeanDescription.forOtherUse(config, type,
149                     _resolveAnnotatedClass(config, type, r));
150         }
151         return desc;
152     }
153
154     @Override
155     public BasicBeanDescription forDirectClassAnnotations(MapperConfig<?> config,
156             JavaType type, MixInResolver r)
157     {
158         BasicBeanDescription desc = _findStdTypeDesc(config, type);
159         if (desc == null) {
160             desc = BasicBeanDescription.forOtherUse(config, type,
161                     _resolveAnnotatedWithoutSuperTypes(config, type, r));
162         }
163         return desc;
164     }
165
166     /*
167     /**********************************************************
168     /* Overridable helper methods
169     /**********************************************************
170      */

171
172     protected POJOPropertiesCollector collectProperties(MapperConfig<?> config,
173             JavaType type, MixInResolver r, boolean forSerialization,
174             String mutatorPrefix)
175     {
176         return constructPropertyCollector(config,
177                 _resolveAnnotatedClass(config, type, r),
178                 type, forSerialization, mutatorPrefix);
179     }
180
181     protected POJOPropertiesCollector collectPropertiesWithBuilder(MapperConfig<?> config,
182             JavaType type, MixInResolver r, boolean forSerialization)
183     {
184         AnnotatedClass ac = _resolveAnnotatedClass(config, type, r);
185         AnnotationIntrospector ai = config.isAnnotationProcessingEnabled() ? config.getAnnotationIntrospector() : null;
186         JsonPOJOBuilder.Value builderConfig = (ai == null) ? null : ai.findPOJOBuilderConfig(ac);
187         String mutatorPrefix = (builderConfig == null) ? JsonPOJOBuilder.DEFAULT_WITH_PREFIX : builderConfig.withPrefix;
188         return constructPropertyCollector(config, ac, type, forSerialization, mutatorPrefix);
189     }
190
191     /**
192      * Overridable method called for creating {@link POJOPropertiesCollector} instance
193      * to use; override is needed if a custom sub-class is to be used.
194      */

195     protected POJOPropertiesCollector constructPropertyCollector(MapperConfig<?> config,
196             AnnotatedClass ac, JavaType type, boolean forSerialization, String mutatorPrefix)
197     {
198         return new POJOPropertiesCollector(config, forSerialization, type, ac, mutatorPrefix);
199     }
200
201     /**
202      * Method called to see if type is one of core JDK types
203      * that we have cached for efficiency.
204      */

205     protected BasicBeanDescription _findStdTypeDesc(MapperConfig<?> config, JavaType type)
206     {
207         Class<?> cls = type.getRawClass();
208         if (cls.isPrimitive()) {
209             if (cls == Integer.TYPE) {
210                 return INT_DESC;
211             }
212             if (cls == Long.TYPE) {
213                 return LONG_DESC;
214             }
215             if (cls == Boolean.TYPE) {
216                 return BOOLEAN_DESC;
217             }
218         } else if (ClassUtil.isJDKClass(cls)) {
219             if (cls == CLS_OBJECT) {
220                 return OBJECT_DESC;
221             }
222             if (cls == CLS_STRING) {
223                 return STRING_DESC;
224             }
225             if (cls == Integer.class) {
226                 return INT_DESC;
227             }
228             if (cls == Long.class) {
229                 return LONG_DESC;
230             }
231             if (cls == Boolean.class) {
232                 return BOOLEAN_DESC;
233             }
234         } else if (CLS_JSON_NODE.isAssignableFrom(cls)) {
235             return BasicBeanDescription.forOtherUse(config, type,
236                     AnnotatedClassResolver.createPrimordial(cls));
237         }
238         return null;
239     }
240
241     /**
242      * Helper method used to decide whether we can omit introspection
243      * for members (methods, fields, constructors); we may do so for
244      * a limited number of container types JDK provides.
245      */

246     protected boolean _isStdJDKCollection(JavaType type)
247     {
248         if (!type.isContainerType() || type.isArrayType()) {
249             return false;
250         }
251         Class<?> raw = type.getRawClass();
252         if (ClassUtil.isJDKClass(raw)) {
253             // 23-Sep-2014, tatu: Should we be conservative here (minimal number
254             //    of matches), or ambitious? Let's do latter for now.
255             if (Collection.class.isAssignableFrom(raw)
256                     || Map.class.isAssignableFrom(raw)) {
257                 return true;
258             }
259         }
260         return false;
261     }
262
263     protected BasicBeanDescription _findStdJdkCollectionDesc(MapperConfig<?> cfg, JavaType type)
264     {
265         if (_isStdJDKCollection(type)) {
266             return BasicBeanDescription.forOtherUse(cfg, type,
267                     _resolveAnnotatedClass(cfg, type, cfg));
268         }
269         return null;
270     }
271
272     /**
273      * @since 2.9
274      */

275     protected AnnotatedClass _resolveAnnotatedClass(MapperConfig<?> config,
276             JavaType type, MixInResolver r) {
277         return AnnotatedClassResolver.resolve(config, type, r);
278     }
279
280     /**
281      * @since 2.9
282      */

283     protected AnnotatedClass _resolveAnnotatedWithoutSuperTypes(MapperConfig<?> config,
284             JavaType type, MixInResolver r) {
285         return AnnotatedClassResolver.resolveWithoutSuperTypes(config, type, r);
286     }
287 }
288