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      */
JavaType(Class<?> raw, int additionalHash, Object valueHandler, Object typeHandler, boolean asStatic)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      */
JavaType(JavaType base)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      */
withTypeHandler(Object h)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      */
withContentTypeHandler(Object h)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      */
withValueHandler(Object h)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      */
withContentValueHandler(Object h)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      */
withHandlersFrom(JavaType src)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      */
withContentType(JavaType contentType)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      */
withStaticTyping()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      */
refine(Class<?> rawType, TypeBindings bindings, JavaType superClass, JavaType[] superInterfaces)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
forcedNarrowBy(Class<?> subclass)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
_narrow(Class<?> subclass)219     protected abstract JavaType _narrow(Class<?> subclass);
220 
221     /*
222     /**********************************************************
223     /* Implementation of ResolvedType API
224     /**********************************************************
225      */
226 
227     @Override
getRawClass()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
hasRawClass(Class<?> clz)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      */
hasContentType()245     public boolean hasContentType() {
246         return true;
247     }
248 
249     /**
250      * @since 2.6
251      */
isTypeOrSubTypeOf(Class<?> clz)252     public final boolean isTypeOrSubTypeOf(Class<?> clz) {
253         return (_class == clz) || clz.isAssignableFrom(_class);
254     }
255 
256     /**
257      * @since 2.9
258      */
isTypeOrSuperTypeOf(Class<?> clz)259     public final boolean isTypeOrSuperTypeOf(Class<?> clz) {
260         return (_class == clz) || _class.isAssignableFrom(clz);
261     }
262 
263     @Override
isAbstract()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
isConcrete()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
isThrowable()286     public boolean isThrowable() { return Throwable.class.isAssignableFrom(_class); }
287 
288     @Override
isArrayType()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
isEnumType()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      */
isEnumImplType()311     public final boolean isEnumImplType() {
312         return ClassUtil.isEnumType(_class) && (_class != Enum.class);
313     }
314 
315     @Override
isInterface()316     public final boolean isInterface() { return _class.isInterface(); }
317 
318     @Override
isPrimitive()319     public final boolean isPrimitive() { return _class.isPrimitive(); }
320 
321     @Override
isFinal()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
isContainerType()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
isCollectionLikeType()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
isMapLikeType()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      */
isJavaLangObject()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      */
useStaticType()366     public final boolean useStaticType() { return _asStatic; }
367 
368     /*
369     /**********************************************************
370     /* Public API, type parameter access; pass-through
371     /**********************************************************
372      */
373 
374     @Override
hasGenericTypes()375     public boolean hasGenericTypes() { return containedTypeCount() > 0; }
376 
377     @Override
getKeyType()378     public JavaType getKeyType() { return null; }
379 
380     @Override
getContentType()381     public JavaType getContentType() { return null; }
382 
383     @Override // since 2.6
getReferencedType()384     public JavaType getReferencedType() { return null; }
385 
386     @Override
containedTypeCount()387     public abstract int containedTypeCount();
388 
389     @Override
containedType(int index)390     public abstract JavaType containedType(int index);
391 
392     @Deprecated // since 2.7
393     @Override
containedTypeName(int index)394     public abstract String containedTypeName(int index);
395 
396     @Deprecated // since 2.7
397     @Override
getParameterSource()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      */
containedTypeOrUnknown(int index)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      */
getBindings()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      */
findSuperType(Class<?> erasedTarget)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      */
getSuperClass()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      */
getInterfaces()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      */
findTypeParameters(Class<?> expType)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")
getValueHandler()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")
getTypeHandler()485     public <T> T getTypeHandler() { return (T) _typeHandler; }
486 
487     /**
488      * @since 2.7
489      */
getContentValueHandler()490     public Object getContentValueHandler() { return null; }
491 
492     /**
493      * @since 2.7
494      */
getContentTypeHandler()495     public Object getContentTypeHandler() { return null; }
496 
497     /**
498      * @since 2.6
499      */
hasValueHandler()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      */
hasHandlers()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      */
getGenericSignature()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      */
getGenericSignature(StringBuilder sb)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      */
getErasedSignature()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      */
getErasedSignature(StringBuilder sb)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
toString()577     public abstract String toString();
578 
579     @Override
equals(Object o)580     public abstract boolean equals(Object o);
581 
582     @Override
hashCode()583     public final int hashCode() { return _hash; }
584 }
585