1 package com.fasterxml.jackson.databind.type;
2
3 import java.util.*;
4
5 import com.fasterxml.jackson.databind.JavaType;
6
7 /**
8  * Simple types are defined as anything other than one of recognized
9  * container types (arrays, Collections, Maps). For our needs we
10  * need not know anything further, since we have no way of dealing
11  * with generic types other than Collections and Maps.
12  */

13 public class SimpleType // note: until 2.6 was final
14     extends TypeBase
15 {
16     private static final long serialVersionUID = 1L;
17
18     /*
19     /**********************************************************
20     /* Life-cycle
21     /**********************************************************
22      */

23
24     /**
25      * Constructor only used by core Jackson databind functionality;
26      * should never be called by application code.
27      *<p>
28      * As with other direct construction that by-passes {@link TypeFactory},
29      * no introspection occurs with respect to super-types; caller must be
30      * aware of consequences if using this method.
31      */

32     protected SimpleType(Class<?> cls) {
33         this(cls, TypeBindings.emptyBindings(), nullnull);
34     }
35
36     protected SimpleType(Class<?> cls, TypeBindings bindings,
37             JavaType superClass, JavaType[] superInts) {
38         this(cls, bindings, superClass, superInts, nullnullfalse);
39     }
40
41     /**
42      * Simple copy-constructor, usually used when upgrading/refining a simple type
43      * into more specialized type.
44      *
45      * @since 2.7
46      */

47     protected SimpleType(TypeBase base) {
48         super(base);
49     }
50
51     protected SimpleType(Class<?> cls, TypeBindings bindings,
52             JavaType superClass, JavaType[] superInts,
53             Object valueHandler, Object typeHandler, boolean asStatic)
54     {
55         super(cls, bindings, superClass, superInts,
56                 0, valueHandler, typeHandler, asStatic);
57     }
58
59     /**
60      * Pass-through constructor used by {@link ReferenceType}.
61      * 
62      * @since 2.6
63      */

64     protected SimpleType(Class<?> cls, TypeBindings bindings,
65             JavaType superClass, JavaType[] superInts, int extraHash,
66             Object valueHandler, Object typeHandler, boolean asStatic)
67     {
68         super(cls, bindings, superClass, superInts, 
69                 extraHash, valueHandler, typeHandler, asStatic);
70     }
71     
72     /**
73      * Method used by core Jackson classes: NOT to be used by application code:
74      * it does NOT properly handle inspection of super-types, so neither parent
75      * Classes nor implemented Interfaces are accessible with resulting type
76      * instance.
77      *<p>
78      * NOTE: public only because it is called by <code>ObjectMapper</code> which is
79      * not in same package
80      */

81     public static SimpleType constructUnsafe(Class<?> raw) {
82         return new SimpleType(raw, null,
83                 // 18-Oct-2015, tatu: Should be ok to omit possible super-types, right?
84                 nullnullnullnullfalse);
85     }
86
87     /**
88      * Method that should NOT to be used by application code:
89      * it does NOT properly handle inspection of super-types, so neither parent
90      * Classes nor implemented Interfaces are accessible with resulting type
91      * instance. Instead, please use {@link TypeFactory}'s <code>constructType</code>
92      * methods which handle introspection appropriately.
93      *<p>
94      * Note that prior to 2.7, method usage was not limited and would typically
95      * have worked acceptably: the problem comes from inability to resolve super-type
96      * information, for which {@link TypeFactory} is needed.
97      * 
98      * @deprecated Since 2.7
99      */

100     @Deprecated
101     public static SimpleType construct(Class<?> cls)
102     {
103         /* Let's add sanity checks, just to ensure no
104          * Map/Collection entries are constructed
105          */

106         if (Map.class.isAssignableFrom(cls)) {
107             throw new IllegalArgumentException("Cannot construct SimpleType for a Map (class: "+cls.getName()+")");
108         }
109         if (Collection.class.isAssignableFrom(cls)) {
110             throw new IllegalArgumentException("Cannot construct SimpleType for a Collection (class: "+cls.getName()+")");
111         }
112         // ... and while we are at it, not array types either
113         if (cls.isArray()) {
114             throw new IllegalArgumentException("Cannot construct SimpleType for an array (class: "+cls.getName()+")");
115         }
116         TypeBindings b = TypeBindings.emptyBindings();
117         return new SimpleType(cls, b,
118                 _buildSuperClass(cls.getSuperclass(), b), nullnullnullfalse);
119     }
120
121     @Override
122     @Deprecated
123     protected JavaType _narrow(Class<?> subclass)
124     {
125         if (_class == subclass) {
126             return this;
127         }
128         // Should we check that there is a sub-class relationship?
129         // 15-Jan-2016, tatu: Almost yes, but there are some complications with
130         //    placeholder values (`Void`, `NoClass`), so cannot quite do yet.
131         // TODO: fix in 2.9
132         if (!_class.isAssignableFrom(subclass)) {
133             /*
134             throw new IllegalArgumentException("Class "+subclass.getName()+" not sub-type of "
135                     +_class.getName());
136                     */

137             return new SimpleType(subclass, _bindings, this, _superInterfaces,
138                     _valueHandler, _typeHandler, _asStatic);
139         }
140         // Otherwise, stitch together the hierarchy. First, super-class
141         Class<?> next = subclass.getSuperclass();
142         if (next == _class) { // straight up parent class? Great.
143             return new SimpleType(subclass, _bindings, this,
144                     _superInterfaces, _valueHandler, _typeHandler, _asStatic);
145         }
146         if ((next != null) && _class.isAssignableFrom(next)) {
147             JavaType superb = _narrow(next);
148             return new SimpleType(subclass, _bindings, superb,
149                     null, _valueHandler, _typeHandler, _asStatic);
150         }
151         // if not found, try a super-interface
152         Class<?>[] nextI = subclass.getInterfaces();
153         for (Class<?> iface : nextI) {
154             if (iface == _class) { // directly implemented
155                 return new SimpleType(subclass, _bindings, null,
156                         new JavaType[] { this }, _valueHandler, _typeHandler, _asStatic);
157             }
158             if (_class.isAssignableFrom(iface)) { // indirect, so recurse
159                 JavaType superb = _narrow(iface);
160                 return new SimpleType(subclass, _bindings, null,
161                         new JavaType[] { superb }, _valueHandler, _typeHandler, _asStatic);
162             }
163         }
164         // should not get here but...
165         throw new IllegalArgumentException("Internal error: Cannot resolve sub-type for Class "+subclass.getName()+" to "
166                 +_class.getName());
167     }
168     
169     @Override
170     public JavaType withContentType(JavaType contentType) {
171         throw new IllegalArgumentException("Simple types have no content types; cannot call withContentType()");
172     }
173     
174     @Override
175     public SimpleType withTypeHandler(Object h) {
176         if (_typeHandler == h) {
177             return this;
178         }
179         return new SimpleType(_class, _bindings, _superClass, _superInterfaces, _valueHandler, h, _asStatic);
180     }
181
182     @Override
183     public JavaType withContentTypeHandler(Object h) {
184         // no content type, so:
185         throw new IllegalArgumentException("Simple types have no content types; cannot call withContenTypeHandler()");
186     }
187
188     @Override
189     public SimpleType withValueHandler(Object h) {
190         if (h == _valueHandler) {
191             return this;
192         }
193         return new SimpleType(_class, _bindings, _superClass, _superInterfaces, h, _typeHandler, _asStatic);
194     }
195     
196     @Override
197     public  SimpleType withContentValueHandler(Object h) {
198         // no content type, so:
199         throw new IllegalArgumentException("Simple types have no content types; cannot call withContenValueHandler()");
200     }
201
202     @Override
203     public SimpleType withStaticTyping() {
204         return _asStatic ? this : new SimpleType(_class, _bindings,
205                 _superClass, _superInterfaces, _valueHandler, _typeHandler, true);
206     }
207
208     @Override
209     public JavaType refine(Class<?> rawType, TypeBindings bindings,
210             JavaType superClass, JavaType[] superInterfaces) {
211         // SimpleType means something not-specialized, so:
212         return null;
213     }
214
215     @Override
216     protected String buildCanonicalName()
217     {
218         StringBuilder sb = new StringBuilder();
219         sb.append(_class.getName());
220
221         final int count = _bindings.size();
222         if (count > 0) {
223             sb.append('<');
224             for (int i = 0; i < count; ++i) {
225                 JavaType t = containedType(i);
226                 if (i > 0) {
227                     sb.append(',');
228                 }
229                 sb.append(t.toCanonical());
230             }
231             sb.append('>');
232         }
233         return sb.toString();
234     }
235
236     /*
237     /**********************************************************
238     /* Public API
239     /**********************************************************
240      */

241
242     @Override
243     public boolean isContainerType() { return false; }
244     
245     @Override
246     public boolean hasContentType() { return false; }
247
248     @Override
249     public StringBuilder getErasedSignature(StringBuilder sb) {
250         return _classSignature(_class, sb, true);
251     }
252     
253     @Override
254     public StringBuilder getGenericSignature(StringBuilder sb)
255     {
256         _classSignature(_class, sb, false);
257
258         final int count = _bindings.size();
259         if (count > 0) {
260             sb.append('<');
261             for (int i = 0; i < count; ++i) {
262                 sb = containedType(i).getGenericSignature(sb);
263             }
264             sb.append('>');
265         }
266         sb.append(';');
267         return sb;
268     }
269
270     /*
271     /**********************************************************
272     /* Internal methods
273     /**********************************************************
274      */

275
276     /**
277      * Helper method we need to recursively build skeletal representations
278      * of superclasses.
279      * 
280      * @since 2.7 -- remove when not needed (2.8?)
281      */

282     private static JavaType _buildSuperClass(Class<?> superClass, TypeBindings b)
283     {
284         if (superClass == null) {
285             return null;
286         }
287         if (superClass == Object.class) {
288             return TypeFactory.unknownType();
289         }
290         JavaType superSuper = _buildSuperClass(superClass.getSuperclass(), b);
291         return new SimpleType(superClass, b,
292                 superSuper, nullnullnullfalse);
293     }
294
295     /*
296     /**********************************************************
297     /* Standard methods
298     /**********************************************************
299      */

300
301     @Override
302     public String toString()
303     {
304         StringBuilder sb = new StringBuilder(40);
305         sb.append("[simple type, class ").append(buildCanonicalName()).append(']');
306         return sb.toString();
307     }
308
309     @Override
310     public boolean equals(Object o)
311     {
312         if (o == thisreturn true;
313         if (o == nullreturn false;
314         if (o.getClass() != getClass()) return false;
315
316         SimpleType other = (SimpleType) o;
317
318         // Classes must be identical... 
319         if (other._class != this._class) return false;
320
321         // And finally, generic bindings, if any
322         TypeBindings b1 = _bindings;
323         TypeBindings b2 = other._bindings;
324         return b1.equals(b2);
325     }
326 }
327