1 package com.fasterxml.jackson.databind;
2
3 import java.lang.reflect.Modifier;
4 import java.util.List;
5
6 import com.fasterxml.jackson.core.type.ResolvedType;
7 import com.fasterxml.jackson.databind.type.TypeBindings;
8 import com.fasterxml.jackson.databind.type.TypeFactory;
9 import com.fasterxml.jackson.databind.util.ClassUtil;
10
11 /**
12 * Base class for type token classes used both to contain information
13 * and as keys for deserializers.
14 *<p>
15 * Instances can (only) be constructed by
16 * <code>com.fasterxml.jackson.databind.type.TypeFactory</code>.
17 *<p>
18 * Since 2.2 this implements {@link java.lang.reflect.Type} to allow
19 * it to be pushed through interfaces that only expose that type.
20 */
21 public abstract class JavaType
22 extends ResolvedType
23 implements java.io.Serializable, // 2.1
24 java.lang.reflect.Type // 2.2
25 {
26 private static final long serialVersionUID = 1;
27
28 /**
29 * This is the nominal type-erased Class that would be close to the
30 * type represented (but not exactly type, due to type erasure: type
31 * instance may have more information on this).
32 * May be an interface or abstract class, so instantiation
33 * may not be possible.
34 */
35 protected final Class<?> _class;
36
37 protected final int _hash;
38
39 /**
40 * Optional handler (codec) that can be attached to indicate
41 * what to use for handling (serializing, deserializing) values of
42 * this specific type.
43 *<p>
44 * Note: untyped (i.e. caller has to cast) because it is used for
45 * different kinds of handlers, with unrelated types.
46 */
47 protected final Object _valueHandler;
48
49 /**
50 * Optional handler that can be attached to indicate how to handle
51 * additional type metadata associated with this type.
52 *<p>
53 * Note: untyped (i.e. caller has to cast) because it is used for
54 * different kinds of handlers, with unrelated types.
55 */
56 protected final Object _typeHandler;
57
58 /**
59 * Whether entities defined with this type should be handled using
60 * static typing (as opposed to dynamic runtime type) or not.
61 *
62 * @since 2.2
63 */
64 protected final boolean _asStatic;
65
66 /*
67 /**********************************************************
68 /* Life-cycle
69 /**********************************************************
70 */
71
72 /**
73 * @param raw "Raw" (type-erased) class for this type
74 * @param additionalHash Additional hash code to use, in addition
75 * to hash code of the class name
76 */
77 protected JavaType(Class<?> raw, int additionalHash,
78 Object valueHandler, Object typeHandler, boolean asStatic)
79 {
80 _class = raw;
81 _hash = raw.getName().hashCode() + additionalHash;
82 _valueHandler = valueHandler;
83 _typeHandler = typeHandler;
84 _asStatic = asStatic;
85 }
86
87 /**
88 * Copy-constructor used when refining/upgrading type instances.
89 *
90 * @since 2.7
91 */
92 protected JavaType(JavaType base)
93 {
94 _class = base._class;
95 _hash = base._hash;
96 _valueHandler = base._valueHandler;
97 _typeHandler = base._typeHandler;
98 _asStatic = base._asStatic;
99 }
100
101 /**
102 * "Copy method" that will construct a new instance that is identical to
103 * this instance, except that it will have specified type handler assigned.
104 *
105 * @return Newly created type instance
106 */
107 public abstract JavaType withTypeHandler(Object h);
108
109 /**
110 * Mutant factory method that will construct a new instance that is identical to
111 * this instance, except that it will have specified content type (element type
112 * for arrays, value type for Maps and so forth) handler assigned.
113 *
114 * @return Newly created type instance, with given
115 */
116 public abstract JavaType withContentTypeHandler(Object h);
117
118 /**
119 * Mutant factory method that will construct a new instance that is identical to
120 * this instance, except that it will have specified value handler assigned.
121 *
122 * @return Newly created type instance
123 */
124 public abstract JavaType withValueHandler(Object h);
125
126 /**
127 * Mutant factory method that will construct a new instance that is identical to
128 * this instance, except that it will have specified content value handler assigned.
129 *
130 * @return Newly created type instance
131 */
132 public abstract JavaType withContentValueHandler(Object h);
133
134 /**
135 * Mutant factory method that will try to copy handlers that the specified
136 * source type instance had, if any; this must be done recursively where
137 * necessary (as content types may be structured).
138 *
139 * @since 2.8.4
140 */
141 public JavaType withHandlersFrom(JavaType src) {
142 JavaType type = this;
143 Object h = src.getTypeHandler();
144 if (h != _typeHandler) {
145 type = type.withTypeHandler(h);
146 }
147 h = src.getValueHandler();
148 if (h != _valueHandler) {
149 type = type.withValueHandler(h);
150 }
151 return type;
152 }
153
154 /**
155 * Mutant factory method that may be called on structured types
156 * that have a so-called content type (element of arrays, value type
157 * of Maps, referenced type of referential types),
158 * and will construct a new instance that is identical to
159 * this instance, except that it has specified content type, instead of current
160 * one. If content type is already set to given type, <code>this</code> is returned.
161 * If type does not have a content type (which is the case with
162 * <code>SimpleType</code>), {@link IllegalArgumentException}
163 * will be thrown.
164 *
165 * @return Newly created type instance
166 *
167 * @since 2.7
168 */
169 public abstract JavaType withContentType(JavaType contentType);
170
171 /**
172 * Method that can be called to get a type instance that indicates
173 * that values of the type should be handled using "static typing" for purposes
174 * of serialization (as opposed to "dynamic" aka runtime typing):
175 * meaning that no runtime information is needed for determining serializers to use.
176 * The main use case is to allow forcing of specific root value serialization type,
177 * and specifically in resolving serializers for contained types (element types
178 * for arrays, Collections and Maps).
179 *
180 * @since 2.2
181 */
182 public abstract JavaType withStaticTyping();
183
184 /*
185 /**********************************************************
186 /* Type coercion fluent factory methods
187 /**********************************************************
188 */
189
190 /**
191 * Mutant factory method that will try to create and return a sub-type instance
192 * for known parameterized types; for other types will return `null` to indicate
193 * that no just refinement makes necessary sense, without trying to detect
194 * special status through implemented interfaces.
195 *
196 * @since 2.7
197 */
198 public abstract JavaType refine(Class<?> rawType, TypeBindings bindings,
199 JavaType superClass, JavaType[] superInterfaces);
200
201 /**
202 * Legacy method used for forcing sub-typing of this type into
203 * type specified by specific type erasure.
204 * Deprecated as of 2.7 as such specializations really ought to
205 * go through {@link TypeFactory}, not directly via {@link JavaType}.
206 *
207 * @since 2.7
208 */
209 @Deprecated
210 public JavaType forcedNarrowBy(Class<?> subclass)
211 {
212 if (subclass == _class) { // can still optimize for simple case
213 return this;
214 }
215 return _narrow(subclass);
216 }
217
218 @Deprecated // since 2.7
219 protected abstract JavaType _narrow(Class<?> subclass);
220
221 /*
222 /**********************************************************
223 /* Implementation of ResolvedType API
224 /**********************************************************
225 */
226
227 @Override
228 public final Class<?> getRawClass() { return _class; }
229
230 /**
231 * Method that can be used to check whether this type has
232 * specified Class as its type erasure. Put another way, returns
233 * true if instantiation of this Type is given (type-erased) Class.
234 */
235 @Override
236 public final boolean hasRawClass(Class<?> clz) { return _class == clz; }
237
238 /**
239 * Accessor that allows determining whether {@link #getContentType()} should
240 * return a non-null value (that is, there is a "content type") or not.
241 * True if {@link #isContainerType()} or {@link #isReferenceType()} return true.
242 *
243 * @since 2.8
244 */
245 public boolean hasContentType() {
246 return true;
247 }
248
249 /**
250 * @since 2.6
251 */
252 public final boolean isTypeOrSubTypeOf(Class<?> clz) {
253 return (_class == clz) || clz.isAssignableFrom(_class);
254 }
255
256 /**
257 * @since 2.9
258 */
259 public final boolean isTypeOrSuperTypeOf(Class<?> clz) {
260 return (_class == clz) || _class.isAssignableFrom(clz);
261 }
262
263 @Override
264 public boolean isAbstract() {
265 return Modifier.isAbstract(_class.getModifiers());
266 }
267
268 /**
269 * Convenience method for checking whether underlying Java type
270 * is a concrete class or not: abstract classes and interfaces
271 * are not.
272 */
273 @Override
274 public boolean isConcrete() {
275 int mod = _class.getModifiers();
276 if ((mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0) {
277 return true;
278 }
279 /* 19-Feb-2010, tatus: Holy mackarel; primitive types
280 * have 'abstract' flag set...
281 */
282 return _class.isPrimitive();
283 }
284
285 @Override
286 public boolean isThrowable() { return Throwable.class.isAssignableFrom(_class); }
287
288 @Override
289 public boolean isArrayType() { return false; }
290
291 /**
292 * Method that basically does equivalent of:
293 *<pre>
294 * Enum.class.isAssignableFrom(getRawClass())
295 *</pre>
296 * that is, return {@code true} if the underlying type erased class is {@code Enum}
297 * or one its subtypes (Enum implementations).
298 */
299 @Override
300 public final boolean isEnumType() {
301 // 29-Sep-2019, tatu: `Class.isEnum()` not enough to detect custom subtypes.
302 return ClassUtil.isEnumType(_class);
303 }
304
305 /**
306 * Similar to {@link #isEnumType} except does NOT return {@code true}
307 * for {@link java.lang.Enum} (since that is not Enum implementation type).
308 *
309 * @since 2.11
310 */
311 public final boolean isEnumImplType() {
312 return ClassUtil.isEnumType(_class) && (_class != Enum.class);
313 }
314
315 @Override
316 public final boolean isInterface() { return _class.isInterface(); }
317
318 @Override
319 public final boolean isPrimitive() { return _class.isPrimitive(); }
320
321 @Override
322 public final boolean isFinal() { return Modifier.isFinal(_class.getModifiers()); }
323
324 /**
325 * @return True if type represented is a container type; this includes
326 * array, Map and Collection types.
327 */
328 @Override
329 public abstract boolean isContainerType();
330
331 /**
332 * @return True if type is either true {@link java.util.Collection} type,
333 * or something similar (meaning it has at least one type parameter,
334 * which describes type of contents)
335 */
336 @Override
337 public boolean isCollectionLikeType() { return false; }
338
339 /**
340 * @return True if type is either true {@link java.util.Map} type,
341 * or something similar (meaning it has at least two type parameter;
342 * first one describing key type, second value type)
343 */
344 @Override
345 public boolean isMapLikeType() { return false; }
346
347 /**
348 * Convenience method, short-hand for
349 *<code>
350 * getRawClass() == Object.class
351 *</code>
352 * and used to figure if we basically have "untyped" type object.
353 *
354 * @since 2.5
355 */
356 public final boolean isJavaLangObject() { return _class == Object.class; }
357
358 /**
359 * Accessor for checking whether handlers for dealing with values of
360 * this type should use static typing (as opposed to dynamic typing).
361 * Note that while value of 'true' does mean that static typing is to
362 * be used, value of 'false' may still be overridden by other settings.
363 *
364 * @since 2.2
365 */
366 public final boolean useStaticType() { return _asStatic; }
367
368 /*
369 /**********************************************************
370 /* Public API, type parameter access; pass-through
371 /**********************************************************
372 */
373
374 @Override
375 public boolean hasGenericTypes() { return containedTypeCount() > 0; }
376
377 @Override
378 public JavaType getKeyType() { return null; }
379
380 @Override
381 public JavaType getContentType() { return null; }
382
383 @Override // since 2.6
384 public JavaType getReferencedType() { return null; }
385
386 @Override
387 public abstract int containedTypeCount();
388
389 @Override
390 public abstract JavaType containedType(int index);
391
392 @Deprecated // since 2.7
393 @Override
394 public abstract String containedTypeName(int index);
395
396 @Deprecated // since 2.7
397 @Override
398 public Class<?> getParameterSource() {
399 return null;
400 }
401
402 /*
403 /**********************************************************
404 /* Extended API beyond ResolvedType
405 /**********************************************************
406 */
407
408 // NOTE: not defined in Resolved type
409 /**
410 * Convenience method that is functionally same as:
411 *<code>
412 * JavaType t = containedType(index);
413 * if (t == null) {
414 * t = TypeFactory.unknownType();
415 * }
416 *</code>
417 * and typically used to eliminate need for null checks for common case
418 * where we just want to check if containedType is available first; and
419 * if not, use "unknown type" (which translates to <code>java.lang.Object</code>
420 * basically).
421 *
422 * @since 2.5
423 */
424 public JavaType containedTypeOrUnknown(int index) {
425 JavaType t = containedType(index);
426 return (t == null) ? TypeFactory.unknownType() : t;
427 }
428
429 /**
430 * @since 2.7
431 */
432 public abstract TypeBindings getBindings();
433
434 /**
435 * Method that may be called to find representation of given type
436 * within type hierarchy of this type: either this type (if this
437 * type has given erased type), one of its supertypes that has the
438 * erased types, or null if target is neither this type or any of its
439 * supertypes.
440 *
441 * @since 2.7
442 */
443 public abstract JavaType findSuperType(Class<?> erasedTarget);
444
445 /**
446 * Accessor for finding fully resolved parent class of this type,
447 * if it has one; null if not.
448 *
449 * @since 2.7
450 */
451 public abstract JavaType getSuperClass();
452
453 /**
454 * Accessor for finding fully resolved interfaces this type implements,
455 * if any; empty array if none.
456 *
457 * @since 2.7
458 */
459 public abstract List<JavaType> getInterfaces();
460
461 /**
462 * Method that may be used to find paramaterization this type has for
463 * given type-erased generic target type.
464 *
465 * @since 2.7
466 */
467 public abstract JavaType[] findTypeParameters(Class<?> expType);
468
469 /*
470 /**********************************************************
471 /* Semi-public API, accessing handlers
472 /**********************************************************
473 */
474
475 /**
476 * Method for accessing value handler associated with this type, if any
477 */
478 @SuppressWarnings("unchecked")
479 public <T> T getValueHandler() { return (T) _valueHandler; }
480
481 /**
482 * Method for accessing type handler associated with this type, if any
483 */
484 @SuppressWarnings("unchecked")
485 public <T> T getTypeHandler() { return (T) _typeHandler; }
486
487 /**
488 * @since 2.7
489 */
490 public Object getContentValueHandler() { return null; }
491
492 /**
493 * @since 2.7
494 */
495 public Object getContentTypeHandler() { return null; }
496
497 /**
498 * @since 2.6
499 */
500 public boolean hasValueHandler() { return _valueHandler != null; }
501
502 /**
503 * Helper method that checks whether this type, or its (optional) key
504 * or content type has {@link #getValueHandler} or {@link #getTypeHandler()};
505 * that is, are there any non-standard handlers associated with this
506 * type object.
507 *
508 * @since 2.8
509 */
510 public boolean hasHandlers() {
511 return (_typeHandler != null) || (_valueHandler != null);
512 }
513
514 /*
515 /**********************************************************
516 /* Support for producing signatures
517 /**********************************************************
518 */
519
520 //public abstract String toCanonical();
521
522 /**
523 * Method for accessing signature that contains generic
524 * type information, in form compatible with JVM 1.5
525 * as per JLS. It is a superset of {@link #getErasedSignature},
526 * in that generic information can be automatically removed
527 * if necessary (just remove outermost
528 * angle brackets along with content inside)
529 */
530 public String getGenericSignature() {
531 StringBuilder sb = new StringBuilder(40);
532 getGenericSignature(sb);
533 return sb.toString();
534 }
535
536 /**
537 *
538 * @param sb StringBuilder to append signature to
539 *
540 * @return StringBuilder that was passed in; returned to allow
541 * call chaining
542 */
543 public abstract StringBuilder getGenericSignature(StringBuilder sb);
544
545 /**
546 * Method for accessing signature without generic
547 * type information, in form compatible with all versions
548 * of JVM, and specifically used for type descriptions
549 * when generating byte code.
550 */
551 public String getErasedSignature() {
552 StringBuilder sb = new StringBuilder(40);
553 getErasedSignature(sb);
554 return sb.toString();
555 }
556
557 /**
558 * Method for accessing signature without generic
559 * type information, in form compatible with all versions
560 * of JVM, and specifically used for type descriptions
561 * when generating byte code.
562 *
563 * @param sb StringBuilder to append signature to
564 *
565 * @return StringBuilder that was passed in; returned to allow
566 * call chaining
567 */
568 public abstract StringBuilder getErasedSignature(StringBuilder sb);
569
570 /*
571 /**********************************************************
572 /* Standard methods; let's make them abstract to force override
573 /**********************************************************
574 */
575
576 @Override
577 public abstract String toString();
578
579 @Override
580 public abstract boolean equals(Object o);
581
582 @Override
583 public final int hashCode() { return _hash; }
584 }
585