1 package com.fasterxml.jackson.databind.type;
2 
3 import java.lang.reflect.TypeVariable;
4 import java.util.Collection;
5 
6 import com.fasterxml.jackson.databind.JavaType;
7 
8 /**
9  * Type that represents things that act similar to {@link java.util.Collection};
10  * but may or may not be instances of that interface.
11  * This specifically allows framework to check for configuration and annotation
12  * settings used for Map types, and pass these to custom handlers that may be more
13  * familiar with actual type.
14  */
15 public class CollectionLikeType extends TypeBase
16 {
17     private static final long serialVersionUID = 1L;
18 
19     /**
20      * Type of elements in collection
21      */
22     protected final JavaType _elementType;
23 
24     /*
25     /**********************************************************
26     /* Life-cycle
27     /**********************************************************
28      */
29 
CollectionLikeType(Class<?> collT, TypeBindings bindings, JavaType superClass, JavaType[] superInts, JavaType elemT, Object valueHandler, Object typeHandler, boolean asStatic)30     protected CollectionLikeType(Class<?> collT, TypeBindings bindings,
31             JavaType superClass, JavaType[] superInts, JavaType elemT,
32             Object valueHandler, Object typeHandler, boolean asStatic)
33     {
34         super(collT, bindings, superClass, superInts,
35                 elemT.hashCode(), valueHandler, typeHandler, asStatic);
36         _elementType = elemT;
37     }
38 
39     /**
40      * @since 2.7
41      */
CollectionLikeType(TypeBase base, JavaType elemT)42     protected CollectionLikeType(TypeBase base, JavaType elemT)
43     {
44         super(base);
45         _elementType = elemT;
46     }
47 
48     /**
49      * @since 2.7
50      */
construct(Class<?> rawType, TypeBindings bindings, JavaType superClass, JavaType[] superInts, JavaType elemT)51     public static CollectionLikeType construct(Class<?> rawType, TypeBindings bindings,
52             JavaType superClass, JavaType[] superInts, JavaType elemT) {
53         return new CollectionLikeType(rawType, bindings, superClass, superInts, elemT,
54                 null, null, false);
55     }
56 
57     /**
58      * @deprecated Since 2.7, use {@link #upgradeFrom} for constructing instances, given
59      *    pre-resolved {@link SimpleType}.
60      */
61     @Deprecated // since 2.7
construct(Class<?> rawType, JavaType elemT)62     public static CollectionLikeType construct(Class<?> rawType, JavaType elemT) {
63         // First: may need to fabricate TypeBindings (needed for refining into
64         // concrete collection types, as per [databind#1102])
65         TypeVariable<?>[] vars = rawType.getTypeParameters();
66         TypeBindings bindings;
67         if ((vars == null) || (vars.length != 1)) {
68             bindings = TypeBindings.emptyBindings();
69         } else {
70             bindings = TypeBindings.create(rawType, elemT);
71         }
72         return new CollectionLikeType(rawType, bindings,
73                 _bogusSuperClass(rawType), null,
74                 elemT, null, null, false);
75     }
76 
77     /**
78      * Factory method that can be used to "upgrade" a basic type into collection-like
79      * one; usually done via {@link TypeModifier}
80      *
81      * @since 2.7
82      */
upgradeFrom(JavaType baseType, JavaType elementType)83     public static CollectionLikeType upgradeFrom(JavaType baseType, JavaType elementType) {
84         // 19-Oct-2015, tatu: Not sure if and how other types could be used as base;
85         //    will cross that bridge if and when need be
86         if (baseType instanceof TypeBase) {
87             return new CollectionLikeType((TypeBase) baseType, elementType);
88         }
89         throw new IllegalArgumentException("Cannot upgrade from an instance of "+baseType.getClass());
90     }
91 
92     @Override
93     @Deprecated // since 2.7
_narrow(Class<?> subclass)94     protected JavaType _narrow(Class<?> subclass) {
95         return new CollectionLikeType(subclass, _bindings,
96                 _superClass, _superInterfaces, _elementType,
97                 _valueHandler, _typeHandler, _asStatic);
98     }
99 
100     @Override
withContentType(JavaType contentType)101     public JavaType withContentType(JavaType contentType) {
102         if (_elementType == contentType) {
103             return this;
104         }
105         return new CollectionLikeType(_class, _bindings, _superClass, _superInterfaces,
106                 contentType, _valueHandler, _typeHandler, _asStatic);
107     }
108 
109     @Override
withTypeHandler(Object h)110     public CollectionLikeType withTypeHandler(Object h) {
111         return new CollectionLikeType(_class, _bindings,
112                 _superClass, _superInterfaces, _elementType, _valueHandler, h, _asStatic);
113     }
114 
115     @Override
withContentTypeHandler(Object h)116     public CollectionLikeType withContentTypeHandler(Object h)
117     {
118         return new CollectionLikeType(_class, _bindings,
119                 _superClass, _superInterfaces, _elementType.withTypeHandler(h),
120                 _valueHandler, _typeHandler, _asStatic);
121     }
122 
123     @Override
withValueHandler(Object h)124     public CollectionLikeType withValueHandler(Object h) {
125         return new CollectionLikeType(_class, _bindings,
126                 _superClass, _superInterfaces, _elementType, h, _typeHandler, _asStatic);
127     }
128 
129     @Override
withContentValueHandler(Object h)130     public CollectionLikeType withContentValueHandler(Object h) {
131         return new CollectionLikeType(_class, _bindings,
132                 _superClass, _superInterfaces, _elementType.withValueHandler(h),
133                 _valueHandler, _typeHandler, _asStatic);
134     }
135 
136     @Override
withHandlersFrom(JavaType src)137     public JavaType withHandlersFrom(JavaType src) {
138         JavaType type = super.withHandlersFrom(src);
139         JavaType srcCt = src.getContentType();
140         if (srcCt != null) {
141             JavaType ct = _elementType.withHandlersFrom(srcCt);
142             if (ct != _elementType) {
143                 type = type.withContentType(ct);
144             }
145         }
146         return type;
147     }
148 
149     @Override
withStaticTyping()150     public CollectionLikeType withStaticTyping() {
151         if (_asStatic) {
152             return this;
153         }
154         return new CollectionLikeType(_class, _bindings,
155                 _superClass, _superInterfaces, _elementType.withStaticTyping(),
156                 _valueHandler, _typeHandler, true);
157     }
158 
159     @Override
refine(Class<?> rawType, TypeBindings bindings, JavaType superClass, JavaType[] superInterfaces)160     public JavaType refine(Class<?> rawType, TypeBindings bindings,
161             JavaType superClass, JavaType[] superInterfaces) {
162         return new CollectionLikeType(rawType, bindings,
163                 superClass, superInterfaces, _elementType,
164                 _valueHandler, _typeHandler, _asStatic);
165     }
166 
167     /*
168     /**********************************************************
169     /* Public API
170     /**********************************************************
171      */
172 
173     @Override
isContainerType()174     public boolean isContainerType() { return true; }
175 
176     @Override
isCollectionLikeType()177     public boolean isCollectionLikeType() { return true; }
178 
179     @Override
getContentType()180     public JavaType getContentType() { return _elementType; }
181 
182     @Override
getContentValueHandler()183     public Object getContentValueHandler() {
184         return _elementType.getValueHandler();
185     }
186 
187     @Override
getContentTypeHandler()188     public Object getContentTypeHandler() {
189         return _elementType.getTypeHandler();
190     }
191 
192     @Override
hasHandlers()193     public boolean hasHandlers() {
194         return super.hasHandlers() || _elementType.hasHandlers();
195     }
196 
197     @Override
getErasedSignature(StringBuilder sb)198     public StringBuilder getErasedSignature(StringBuilder sb) {
199         return _classSignature(_class, sb, true);
200     }
201 
202     @Override
getGenericSignature(StringBuilder sb)203     public StringBuilder getGenericSignature(StringBuilder sb) {
204         _classSignature(_class, sb, false);
205         sb.append('<');
206         _elementType.getGenericSignature(sb);
207         sb.append(">;");
208         return sb;
209     }
210 
211     @Override
buildCanonicalName()212     protected String buildCanonicalName() {
213         StringBuilder sb = new StringBuilder();
214         sb.append(_class.getName());
215         if (_elementType != null) {
216             sb.append('<');
217             sb.append(_elementType.toCanonical());
218             sb.append('>');
219         }
220         return sb.toString();
221     }
222 
223     /*
224     /**********************************************************
225     /* Extended API
226     /**********************************************************
227      */
228 
229     /**
230      * Method that can be used for checking whether this type is a
231      * "real" Collection type; meaning whether it represents a parameterized
232      * subtype of {@link java.util.Collection} or just something that acts
233      * like one.
234      */
isTrueCollectionType()235     public boolean isTrueCollectionType() {
236         return Collection.class.isAssignableFrom(_class);
237     }
238 
239     /*
240     /**********************************************************
241     /* Standard methods
242     /**********************************************************
243      */
244 
245     @Override
equals(Object o)246     public boolean equals(Object o)
247     {
248         if (o == this) return true;
249         if (o == null) return false;
250         if (o.getClass() != getClass()) return false;
251 
252         CollectionLikeType other = (CollectionLikeType) o;
253         return  (_class == other._class) && _elementType.equals(other._elementType);
254     }
255 
256     @Override
toString()257     public String toString()
258     {
259         return "[collection-like type; class "+_class.getName()+", contains "+_elementType+"]";
260     }
261 
262 }
263