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    }