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