001 /**
002 * Copyright (C) 2009-2011 the original author or authors.
003 * See the notice.md file distributed with this work for additional
004 * information regarding copyright ownership.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019 package org.codehaus.jackson.type;
020
021 import java.lang.reflect.Modifier;
022
023 /**
024 * Base class for type token classes used both to contain information
025 * and as keys for deserializers.
026 *<p>
027 * Instances can (only) be constructed by
028 * {@link org.codehaus.jackson.map.type.TypeFactory}.
029 */
030 public abstract class JavaType
031 {
032 /**
033 * This is the nominal type-erased Class that would be close to the
034 * type represented (but not exactly type, due to type erasure: type
035 * instance may have more information on this).
036 * May be an interface or abstract class, so instantiation
037 * may not be possible.
038 */
039 protected final Class<?> _class;
040
041 protected final int _hashCode;
042
043 /**
044 * Optional handler (codec) that can be attached to indicate
045 * what to use for handling (serializing, deserializing) values of
046 * this specific type.
047 *<p>
048 * Note: untyped (i.e. caller has to cast) because it is used for
049 * different kinds of handlers, with unrelated types.
050 *
051 * @since 1.3
052 */
053 protected Object _valueHandler;
054
055 /**
056 * Optional handler that can be attached to indicate how to handle
057 * additional type metadata associated with this type.
058 *<p>
059 * Note: untyped (i.e. caller has to cast) because it is used for
060 * different kinds of handlers, with unrelated types.
061 *
062 * @since 1.5
063 */
064 protected Object _typeHandler;
065
066 /*
067 /**********************************************************
068 /* Life-cycle
069 /**********************************************************
070 */
071
072 protected JavaType(Class<?> clz, int hash)
073 {
074 _class = clz;
075 String name = clz.getName();
076 _hashCode = name.hashCode() + hash;
077 }
078
079 /**
080 * "Copy method" that will construct a new instance that is identical to
081 * this instance, except that it will have specified type handler assigned.
082 *
083 * @return Newly created type instance
084 *
085 * @since 1.7
086 */
087 public abstract JavaType withTypeHandler(Object h);
088
089 /**
090 * "Copy method" that will construct a new instance that is identical to
091 * this instance, except that its content type will have specified
092 * type handler assigned.
093 *
094 * @return Newly created type instance
095 *
096 * @since 1.7
097 */
098 public abstract JavaType withContentTypeHandler(Object h);
099
100 /**
101 * Method that can be called to do a "narrowing" conversions; that is,
102 * to return a type with a raw class that is assignable to the raw
103 * class of this type. If this is not possible, an
104 * {@link IllegalArgumentException} is thrown.
105 * If class is same as the current raw class, instance itself is
106 * returned.
107 */
108 public final JavaType narrowBy(Class<?> subclass)
109 {
110 // First: if same raw class, just return this instance
111 if (subclass == _class) {
112 return this;
113 }
114 // Otherwise, ensure compatibility
115 _assertSubclass(subclass, _class);
116 JavaType result = _narrow(subclass);
117 if (_valueHandler != null) {
118 result.setValueHandler(_valueHandler);
119 }
120 if (_typeHandler != null) {
121 result = result.withTypeHandler(_typeHandler);
122 }
123 return result;
124 }
125
126 /**
127 * More efficient version of {@link #narrowBy}, called by
128 * internal framework in cases where compatibility checks
129 * are to be skipped.
130 *
131 * @since 1.5
132 */
133 public final JavaType forcedNarrowBy(Class<?> subclass)
134 {
135 if (subclass == _class) { // can still optimize for simple case
136 return this;
137 }
138 JavaType result = _narrow(subclass);
139 if (_valueHandler != null) {
140 result.setValueHandler(_valueHandler);
141 }
142 if (_typeHandler != null) {
143 result = result.withTypeHandler(_typeHandler);
144 }
145 return result;
146 }
147
148 /**
149 * Method that can be called to do a "widening" conversions; that is,
150 * to return a type with a raw class that could be assigned from this
151 * type.
152 * If such conversion is not possible, an
153 * {@link IllegalArgumentException} is thrown.
154 * If class is same as the current raw class, instance itself is
155 * returned.
156 */
157 public final JavaType widenBy(Class<?> superclass)
158 {
159 // First: if same raw class, just return this instance
160 if (superclass == _class) {
161 return this;
162 }
163 // Otherwise, ensure compatibility
164 _assertSubclass(_class, superclass);
165 return _widen(superclass);
166 }
167
168 protected abstract JavaType _narrow(Class<?> subclass);
169
170 /**
171 *<p>
172 * Default implementation is just to call {@link #_narrow}, since
173 * underlying type construction is usually identical
174 */
175 protected JavaType _widen(Class<?> superclass) {
176 return _narrow(superclass);
177 }
178
179 public abstract JavaType narrowContentsBy(Class<?> contentClass);
180
181 /**
182 * @since 1.8
183 */
184 public abstract JavaType widenContentsBy(Class<?> contentClass);
185
186 /**
187 * Method for assigning handler to associate with this type; or
188 * if null passed, to remove such assignment
189 *
190 * @since 1.3
191 */
192 public void setValueHandler(Object h) {
193 // sanity check, should be assigned just once
194 if (h != null && _valueHandler != null) {
195 throw new IllegalStateException("Trying to reset value handler for type ["+toString()
196 +"]; old handler of type "+_valueHandler.getClass().getName()+", new handler of type "+h.getClass().getName());
197 }
198 _valueHandler = h;
199 }
200
201 /**
202 * Method for assigning type handler to associate with this type; or
203 * if null passed, to remove such assignment
204 *
205 * @since 1.5
206 *
207 * @deprecated Used {@link #withTypeHandler} instead -- this method is dangerous as
208 * it changes state, whereas all other functionality is stateless
209 */
210 @Deprecated
211 public void setTypeHandler(Object h)
212 {
213 // sanity check, should be assigned just once
214 /* 03-Nov-2010: NOTE - some care has to be taken to ensure that types are not reused
215 * between requests; one case I had to fix was that of passing root type by ObjectWriter
216 * and ObjectReader (must clone/copy types!)
217 */
218 if (h != null && _typeHandler != null) {
219 throw new IllegalStateException("Trying to reset type handler for type ["+toString()
220 +"]; old handler of type "+_typeHandler.getClass().getName()+", new handler of type "+h.getClass().getName());
221 }
222 _typeHandler = h;
223 }
224
225 /*
226 /**********************************************************
227 /* Public API, simple accessors
228 /**********************************************************
229 */
230
231 public final Class<?> getRawClass() { return _class; }
232
233 /**
234 * Method that can be used to check whether this type has
235 * specified Class as its type erasure. Put another way, returns
236 * true if instantiation of this Type is given (type-erased) Class.
237 */
238 public final boolean hasRawClass(Class<?> clz) {
239 return _class == clz;
240 }
241
242 public boolean isAbstract() {
243 return Modifier.isAbstract(_class.getModifiers());
244 }
245
246 /**
247 * @since 1.3
248 */
249 public boolean isConcrete() {
250 int mod = _class.getModifiers();
251 if ((mod & (Modifier.INTERFACE | Modifier.ABSTRACT)) == 0) {
252 return true;
253 }
254 /* 19-Feb-2010, tatus: Holy mackarel; primitive types
255 * have 'abstract' flag set...
256 */
257 if (_class.isPrimitive()) {
258 return true;
259 }
260 return false;
261 }
262
263 public boolean isThrowable() {
264 return Throwable.class.isAssignableFrom(_class);
265 }
266
267 public boolean isArrayType() { return false; }
268
269 public final boolean isEnumType() { return _class.isEnum(); }
270
271 public final boolean isInterface() { return _class.isInterface(); }
272
273 public final boolean isPrimitive() { return _class.isPrimitive(); }
274
275 public final boolean isFinal() { return Modifier.isFinal(_class.getModifiers()); }
276
277 /**
278 * @return True if type represented is a container type; this includes
279 * array, Map and Collection types.
280 */
281 public abstract boolean isContainerType();
282
283 /**
284 * @return True if type is either true {@link java.util.Collection} type,
285 * or something similar (meaning it has at least one type parameter,
286 * which describes type of contents)
287 *
288 * @since 1.8
289 */
290 public boolean isCollectionLikeType() { return false; }
291
292 /**
293 * @return True if type is either true {@link java.util.Map} type,
294 * or something similar (meaning it has at least two type parameter;
295 * first one describing key type, second value type)
296 *
297 * @since 1.8
298 */
299 public boolean isMapLikeType() { return false; }
300
301 /*
302 /**********************************************************
303 /* Public API, type parameter access
304 /**********************************************************
305 */
306
307 /**
308 * Method that can be used to find out if the type directly declares generic
309 * parameters (for its direct super-class and/or super-interfaces).
310 *
311 * @since 1.6
312 */
313 public boolean hasGenericTypes()
314 {
315 return containedTypeCount() > 0;
316 }
317
318 /**
319 * Method for accessing key type for this type, assuming type
320 * has such a concept (only Map types do)
321 */
322 public JavaType getKeyType() { return null; }
323
324 /**
325 * Method for accessing content type of this type, if type has
326 * such a thing: simple types do not, structured types do
327 * (like arrays, Collections and Maps)
328 */
329 public JavaType getContentType() { return null; }
330
331 /**
332 * Method for checking how many contained types this type
333 * has. Contained types are usually generic types, so that
334 * generic Maps have 2 contained types.
335 *
336 * @since 1.5
337 */
338 public int containedTypeCount() { return 0; }
339
340 /**
341 * Method for accessing definitions of contained ("child")
342 * types.
343 *
344 * @param index Index of contained type to return
345 *
346 * @return Contained type at index, or null if no such type
347 * exists (no exception thrown)
348 *
349 * @since 1.5
350 */
351 public JavaType containedType(int index) { return null; }
352
353 /**
354 * Method for accessing name of type variable in indicated
355 * position. If no name is bound, will use placeholders (derived
356 * from 0-based index); if no type variable or argument exists
357 * with given index, null is returned.
358 *
359 * @param index Index of contained type to return
360 *
361 * @return Contained type at index, or null if no such type
362 * exists (no exception thrown)
363 *
364 * @since 1.5
365 */
366 public String containedTypeName(int index) { return null; }
367
368 /*
369 /**********************************************************
370 /* Semi-public API, accessing handlers
371 /**********************************************************
372 */
373
374 /**
375 * Method for accessing value handler associated with this type, if any
376 *
377 * @since 1.3
378 */
379 @SuppressWarnings("unchecked")
380 public <T> T getValueHandler() { return (T) _valueHandler; }
381
382 /**
383 * Method for accessing type handler associated with this type, if any
384 *
385 * @since 1.5
386 */
387 @SuppressWarnings("unchecked")
388 public <T> T getTypeHandler() { return (T) _typeHandler; }
389
390 /*
391 /**********************************************************
392 /* Support for producing signatures (1.6+)
393 /**********************************************************
394 */
395
396 /**
397 * Method that can be used to serialize type into form from which
398 * it can be fully deserialized from at a later point (using
399 * <code>TypeFactory</code> from mapper package).
400 * For simple types this is same as calling
401 * {@link Class#getName}, but for structured types it may additionally
402 * contain type information about contents.
403 *
404 * @since 1.5
405 */
406 public abstract String toCanonical();
407
408 /**
409 * Method for accessing signature that contains generic
410 * type information, in form compatible with JVM 1.5
411 * as per JLS. It is a superset of {@link #getErasedSignature},
412 * in that generic information can be automatically removed
413 * if necessary (just remove outermost
414 * angle brackets along with content inside)
415 *
416 * @since 1.6
417 */
418 public String getGenericSignature() {
419 StringBuilder sb = new StringBuilder(40);
420 getGenericSignature(sb);
421 return sb.toString();
422 }
423
424 /**
425 *
426 * @param sb StringBuilder to append signature to
427 *
428 * @return StringBuilder that was passed in; returned to allow
429 * call chaining
430 *
431 * @since 1.6
432 */
433 public abstract StringBuilder getGenericSignature(StringBuilder sb);
434
435 /**
436 * Method for accessing signature without generic
437 * type information, in form compatible with all versions
438 * of JVM, and specifically used for type descriptions
439 * when generating byte code.
440 *
441 * @since 1.6
442 */
443 public String getErasedSignature() {
444 StringBuilder sb = new StringBuilder(40);
445 getErasedSignature(sb);
446 return sb.toString();
447 }
448
449 /**
450 * Method for accessing signature without generic
451 * type information, in form compatible with all versions
452 * of JVM, and specifically used for type descriptions
453 * when generating byte code.
454 *
455 * @param sb StringBuilder to append signature to
456 *
457 * @return StringBuilder that was passed in; returned to allow
458 * call chaining
459 *
460 * @since 1.6
461 */
462 public abstract StringBuilder getErasedSignature(StringBuilder sb);
463
464 /*
465 /**********************************************************
466 /* Helper methods
467 /**********************************************************
468 */
469
470 protected void _assertSubclass(Class<?> subclass, Class<?> superClass)
471 {
472 if (!_class.isAssignableFrom(subclass)) {
473 throw new IllegalArgumentException("Class "+subclass.getName()+" is not assignable to "+_class.getName());
474 }
475 }
476
477 /*
478 /**********************************************************
479 /* Standard methods; let's make them abstract to force override
480 /**********************************************************
481 */
482
483 @Override
484 public abstract String toString();
485
486 @Override
487 public abstract boolean equals(Object o);
488
489 @Override
490 public final int hashCode() { return _hashCode; }
491 }