blob: 8ddb4f45d5bc727343b0b39c0f2b0d9889f45d5e [file] [log] [blame]
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08001package com.fasterxml.jackson.databind.jsontype.impl;
2
3import java.io.IOException;
4import java.util.HashMap;
5
Tatu Saloranta1b253d32011-12-23 00:44:25 -08006import com.fasterxml.jackson.annotation.JsonTypeInfo;
7import com.fasterxml.jackson.core.*;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -08008import com.fasterxml.jackson.databind.BeanProperty;
9import com.fasterxml.jackson.databind.DeserializationContext;
Tatu Saloranta192c1dc2013-02-06 22:28:58 -080010import com.fasterxml.jackson.databind.DeserializationFeature;
Tatu Salorantad92c1ed2011-12-23 18:23:31 -080011import com.fasterxml.jackson.databind.JavaType;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080012import com.fasterxml.jackson.databind.JsonDeserializer;
Tatu Saloranta192c1dc2013-02-06 22:28:58 -080013import com.fasterxml.jackson.databind.deser.std.NullifyingDeserializer;
Tatu Salorantadf6302f2011-12-23 20:05:35 -080014import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080015import com.fasterxml.jackson.databind.jsontype.TypeIdResolver;
Tatu Saloranta46c66792014-05-19 23:42:47 -070016import com.fasterxml.jackson.databind.util.ClassUtil;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080017
18/**
Tatu Salorantab2a9ca72012-01-20 20:16:21 -080019 * Base class for all standard Jackson {@link TypeDeserializer}s.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080020 */
Tatu Saloranta65d186e2012-10-05 23:51:38 -070021public abstract class TypeDeserializerBase
22 extends TypeDeserializer
23 implements java.io.Serializable
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080024{
Tatu Saloranta65d186e2012-10-05 23:51:38 -070025 private static final long serialVersionUID = 278445030337366675L;
Tatu Saloranta192c1dc2013-02-06 22:28:58 -080026
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080027 protected final TypeIdResolver _idResolver;
28
29 protected final JavaType _baseType;
30
Tatu Saloranta49b71212012-01-30 22:13:21 -080031 /**
32 * Property that contains value for which type information
33 * is included; null if value is a root value.
34 * Note that this value is not assigned during construction
35 * but only when {@link #forProperty} is called to create
36 * a copy.
37 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080038 protected final BeanProperty _property;
39
40 /**
41 * Type to use as the default implementation, if type id is
42 * missing or can not be resolved.
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080043 */
44 protected final JavaType _defaultImpl;
Tatu Saloranta89580482012-01-20 22:08:56 -080045
46 /**
47 * Name of type property used; needed for non-property versions too,
48 * in cases where type id is to be exposed as part of JSON.
49 */
50 protected final String _typePropertyName;
51
52 protected final boolean _typeIdVisible;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080053
54 /**
55 * For efficient operation we will lazily build mappings from type ids
56 * to actual deserializers, once needed.
57 */
58 protected final HashMap<String,JsonDeserializer<Object>> _deserializers;
59
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080060 protected JsonDeserializer<Object> _defaultImplDeserializer;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080061
Tatu Saloranta49b71212012-01-30 22:13:21 -080062 /*
63 /**********************************************************
64 /* Life-cycle
65 /**********************************************************
66 */
67
68 protected TypeDeserializerBase(JavaType baseType, TypeIdResolver idRes,
Tatu Saloranta89580482012-01-20 22:08:56 -080069 String typePropertyName, boolean typeIdVisible, Class<?> defaultImpl)
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080070 {
71 _baseType = baseType;
72 _idResolver = idRes;
Tatu Saloranta89580482012-01-20 22:08:56 -080073 _typePropertyName = typePropertyName;
74 _typeIdVisible = typeIdVisible;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080075 _deserializers = new HashMap<String,JsonDeserializer<Object>>();
76 if (defaultImpl == null) {
77 _defaultImpl = null;
78 } else {
79 /* 16-Oct-2011, tatu: should call this via TypeFactory; this is
80 * not entirely safe... however, since Collections/Maps are
81 * seldom (if ever) base types, may be ok.
82 */
83 _defaultImpl = baseType.forcedNarrowBy(defaultImpl);
84 }
Tatu Saloranta49b71212012-01-30 22:13:21 -080085
86 _property = null;
Tatu Salorantae4f23bb2011-12-23 00:31:35 -080087 }
88
Tatu Saloranta49b71212012-01-30 22:13:21 -080089 protected TypeDeserializerBase(TypeDeserializerBase src, BeanProperty property)
90 {
91 _baseType = src._baseType;
92 _idResolver = src._idResolver;
93 _typePropertyName = src._typePropertyName;
94 _typeIdVisible = src._typeIdVisible;
95 _deserializers = src._deserializers;
96 _defaultImpl = src._defaultImpl;
97 _defaultImplDeserializer = src._defaultImplDeserializer;
98
99 _property = property;
100 }
101
102 @Override
103 public abstract TypeDeserializer forProperty(BeanProperty prop);
104
105 /*
106 /**********************************************************
107 /* Accessors
108 /**********************************************************
109 */
110
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800111 @Override
112 public abstract JsonTypeInfo.As getTypeInclusion();
113
114 public String baseTypeName() { return _baseType.getRawClass().getName(); }
115
116 @Override
Tatu Saloranta89580482012-01-20 22:08:56 -0800117 public final String getPropertyName() { return _typePropertyName; }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800118
119 @Override
120 public TypeIdResolver getTypeIdResolver() { return _idResolver; }
121
122 @Override
123 public Class<?> getDefaultImpl() {
124 return (_defaultImpl == null) ? null : _defaultImpl.getRawClass();
125 }
126
127 @Override
128 public String toString()
129 {
Tatu Salorantaa795fa22013-01-18 20:05:11 -0800130 StringBuilder sb = new StringBuilder();
131 sb.append('[').append(getClass().getName());
132 sb.append("; base-type:").append(_baseType);
133 sb.append("; id-resolver: ").append(_idResolver);
134 sb.append(']');
135 return sb.toString();
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800136 }
137
138 /*
139 /**********************************************************
140 /* Helper methods for sub-classes
141 /**********************************************************
142 */
143
Tatu Salorantab6da8662014-05-04 18:49:20 -0700144 protected final JsonDeserializer<Object> _findDeserializer(DeserializationContext ctxt, String typeId)
145 throws IOException
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800146 {
147 JsonDeserializer<Object> deser;
148
149 synchronized (_deserializers) {
150 deser = _deserializers.get(typeId);
151 if (deser == null) {
Tatu Salorantaee67dee2013-09-28 17:11:46 -0700152 /* As per [Issue#305], need to provide contextual info. But for
153 * backwards compatibility, let's start by only supporting this
154 * for base class, not via interface. Later on we can add this
155 * to the interface, assuming deprecation at base class helps.
156 */
157 JavaType type;
158 if (_idResolver instanceof TypeIdResolverBase) {
159 type = ((TypeIdResolverBase) _idResolver).typeFromId(ctxt, typeId);
160 } else {
161 type = _idResolver.typeFromId(typeId);
162 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800163 if (type == null) {
164 // As per [JACKSON-614], use the default impl if no type id available:
165 if (_defaultImpl == null) {
166 throw ctxt.unknownTypeException(_baseType, typeId);
167 }
168 deser = _findDefaultImplDeserializer(ctxt);
169 } else {
170 /* 16-Dec-2010, tatu: Since nominal type we get here has no (generic) type parameters,
171 * we actually now need to explicitly narrow from base type (which may have parameterization)
172 * using raw type.
173 *
174 * One complication, though; can not change 'type class' (simple type to container); otherwise
175 * we may try to narrow a SimpleType (Object.class) into MapType (Map.class), losing actual
176 * type in process (getting SimpleType of Map.class which will not work as expected)
177 */
178 if (_baseType != null && _baseType.getClass() == type.getClass()) {
179 type = _baseType.narrowBy(type.getRawClass());
180 }
Tatuc3a73d02012-01-31 12:45:49 -0800181 deser = ctxt.findContextualValueDeserializer(type, _property);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800182 }
183 _deserializers.put(typeId, deser);
184 }
185 }
186 return deser;
187 }
188
Tatu Salorantab6da8662014-05-04 18:49:20 -0700189 protected final JsonDeserializer<Object> _findDefaultImplDeserializer(DeserializationContext ctxt) throws IOException
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800190 {
Tatu Saloranta192c1dc2013-02-06 22:28:58 -0800191 /* 06-Feb-2013, tatu: As per [Issue#148], consider default implementation value of
Tatu Saloranta97a0dea2014-05-19 23:55:15 -0700192 * {@link java.lang.Void} to mean "serialize as null"; as well as DeserializationFeature
Tatu Saloranta192c1dc2013-02-06 22:28:58 -0800193 * to do swift mapping to null
194 */
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800195 if (_defaultImpl == null) {
Tatu Saloranta192c1dc2013-02-06 22:28:58 -0800196 if (!ctxt.isEnabled(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE)) {
197 return NullifyingDeserializer.instance;
198 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800199 return null;
200 }
Tatu Saloranta46c66792014-05-19 23:42:47 -0700201 Class<?> raw = _defaultImpl.getRawClass();
202 if (ClassUtil.isBogusClass(raw)) {
Tatu Saloranta192c1dc2013-02-06 22:28:58 -0800203 return NullifyingDeserializer.instance;
204 }
205
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800206 synchronized (_defaultImpl) {
207 if (_defaultImplDeserializer == null) {
Tatuc3a73d02012-01-31 12:45:49 -0800208 _defaultImplDeserializer = ctxt.findContextualValueDeserializer(
209 _defaultImpl, _property);
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800210 }
211 return _defaultImplDeserializer;
212 }
213 }
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700214
215 /**
216 * Helper method called when {@link JsonParser} indicates that it can use
217 * so-called native type ids. Assumption from there is that only native
218 * type ids are to be used.
219 *
220 * @since 2.3
221 */
Tatu Salorantab6da8662014-05-04 18:49:20 -0700222 @Deprecated
223 protected Object _deserializeWithNativeTypeId(JsonParser jp, DeserializationContext ctxt) throws IOException {
224 return _deserializeWithNativeTypeId(jp, ctxt, jp.getTypeId());
225 }
226
227 /**
228 * Helper method called when {@link JsonParser} indicates that it can use
229 * so-called native type ids, and such type id has been found.
230 *
231 * @since 2.4
232 */
233 protected Object _deserializeWithNativeTypeId(JsonParser jp, DeserializationContext ctxt, Object typeId)
Tatu Saloranta5bdafdc2014-05-04 19:52:56 -0700234 throws IOException
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700235 {
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700236 JsonDeserializer<Object> deser;
Tatu Salorantab6da8662014-05-04 18:49:20 -0700237 if (typeId == null) {
238 /* 04-May-2014, tatu: Should error be obligatory, or should there be another method
239 * for "try to deserialize with native tpye id"?
240 */
241 if (_defaultImpl == null) {
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700242 throw ctxt.mappingException("No (native) type id found when one was expected for polymorphic type handling");
243 }
Tatu Salorantab6da8662014-05-04 18:49:20 -0700244 deser = _findDefaultImplDeserializer(ctxt);
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700245 } else {
Tatu Salorantab6da8662014-05-04 18:49:20 -0700246 String typeIdStr = (typeId instanceof String) ? (String) typeId : String.valueOf(typeId);
247 deser = _findDeserializer(ctxt, typeIdStr);
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700248 }
Tatu Saloranta8b5fd602013-08-03 13:41:28 -0700249 return deser.deserialize(jp, ctxt);
250 }
Tatu Salorantae4f23bb2011-12-23 00:31:35 -0800251}