1 package com.fasterxml.jackson.databind.deser; 2 3 import java.io.IOException; 4 import java.util.*; 5 import java.util.Map.Entry; 6 7 import com.fasterxml.jackson.annotation.ObjectIdGenerator; 8 import com.fasterxml.jackson.annotation.ObjectIdResolver; 9 import com.fasterxml.jackson.annotation.ObjectIdGenerator.IdKey; 10 11 import com.fasterxml.jackson.core.JsonParser; 12 import com.fasterxml.jackson.core.JsonToken; 13 import com.fasterxml.jackson.databind.*; 14 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 15 import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId; 16 import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring; 17 import com.fasterxml.jackson.databind.introspect.Annotated; 18 import com.fasterxml.jackson.databind.util.ClassUtil; 19 20 /** 21 * Complete {@link DeserializationContext} implementation that adds 22 * extended API for {@link ObjectMapper} (and {@link ObjectReader}) 23 * to call, as well as implements certain parts that base class 24 * has left abstract. 25 * The remaining abstract methods ({@link #createInstance}, {@link #with}) 26 * are left so that custom implementations will properly implement them 27 * to return intended subtype. 28 */ 29 public abstract class DefaultDeserializationContext 30 extends DeserializationContext 31 implements java.io.Serializable // since 2.1 32 { 33 private static final long serialVersionUID = 1L; 34 35 protected transient LinkedHashMap<ObjectIdGenerator.IdKey, ReadableObjectId> _objectIds; 36 37 private List<ObjectIdResolver> _objectIdResolvers; 38 39 /** 40 * Constructor that will pass specified deserializer factory and 41 * cache: cache may be null (in which case default implementation 42 * will be used), factory cannot be null 43 */ DefaultDeserializationContext(DeserializerFactory df, DeserializerCache cache)44 protected DefaultDeserializationContext(DeserializerFactory df, DeserializerCache cache) { 45 super(df, cache); 46 } 47 DefaultDeserializationContext(DefaultDeserializationContext src, DeserializationConfig config, JsonParser p, InjectableValues values)48 protected DefaultDeserializationContext(DefaultDeserializationContext src, 49 DeserializationConfig config, JsonParser p, InjectableValues values) { 50 super(src, config, p, values); 51 } 52 53 // @since 2.12 DefaultDeserializationContext(DefaultDeserializationContext src, DeserializationConfig config)54 protected DefaultDeserializationContext(DefaultDeserializationContext src, 55 DeserializationConfig config) { 56 super(src, config); 57 } 58 DefaultDeserializationContext(DefaultDeserializationContext src, DeserializerFactory factory)59 protected DefaultDeserializationContext(DefaultDeserializationContext src, 60 DeserializerFactory factory) { 61 super(src, factory); 62 } 63 64 /** 65 * @since 2.4.4 66 */ DefaultDeserializationContext(DefaultDeserializationContext src)67 protected DefaultDeserializationContext(DefaultDeserializationContext src) { 68 super(src); 69 } 70 71 /** 72 * Method needed to ensure that {@link ObjectMapper#copy} will work 73 * properly; specifically, that caches are cleared, but settings 74 * will otherwise remain identical; and that no sharing of state 75 * occurs. 76 * 77 * @since 2.4.4 78 */ copy()79 public DefaultDeserializationContext copy() { 80 throw new IllegalStateException("DefaultDeserializationContext sub-class not overriding copy()"); 81 } 82 83 /* 84 /********************************************************** 85 /* Abstract methods impls, Object Id 86 /********************************************************** 87 */ 88 89 @Override findObjectId(Object id, ObjectIdGenerator<?> gen, ObjectIdResolver resolverType)90 public ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> gen, ObjectIdResolver resolverType) 91 { 92 // 02-Apr-2015, tatu: As per [databind#742] should allow 'null', similar to how 93 // missing id already works. 94 if (id == null) { 95 return null; 96 } 97 98 final ObjectIdGenerator.IdKey key = gen.key(id); 99 100 if (_objectIds == null) { 101 _objectIds = new LinkedHashMap<ObjectIdGenerator.IdKey,ReadableObjectId>(); 102 } else { 103 ReadableObjectId entry = _objectIds.get(key); 104 if (entry != null) { 105 return entry; 106 } 107 } 108 109 // Not seen yet, must create entry and configure resolver. 110 ObjectIdResolver resolver = null; 111 112 if (_objectIdResolvers == null) { 113 _objectIdResolvers = new ArrayList<ObjectIdResolver>(8); 114 } else { 115 for (ObjectIdResolver res : _objectIdResolvers) { 116 if (res.canUseFor(resolverType)) { 117 resolver = res; 118 break; 119 } 120 } 121 } 122 123 if (resolver == null) { 124 resolver = resolverType.newForDeserialization(this); 125 _objectIdResolvers.add(resolver); 126 } 127 128 ReadableObjectId entry = createReadableObjectId(key); 129 entry.setResolver(resolver); 130 _objectIds.put(key, entry); 131 return entry; 132 } 133 134 /** 135 * Overridable factory method to create a new instance of ReadableObjectId or its 136 * subclass. It is meant to be overridden when custom ReadableObjectId is 137 * needed for {@link #tryToResolveUnresolvedObjectId}. 138 * Default implementation simply constructs default {@link ReadableObjectId} with 139 * given <code>key</code>. 140 * 141 * @param key The key to associate with the new ReadableObjectId 142 * @return New ReadableObjectId instance 143 * 144 * @since 2.7 145 */ createReadableObjectId(IdKey key)146 protected ReadableObjectId createReadableObjectId(IdKey key) { 147 return new ReadableObjectId(key); 148 } 149 150 @Override checkUnresolvedObjectId()151 public void checkUnresolvedObjectId() throws UnresolvedForwardReference 152 { 153 if (_objectIds == null) { 154 return; 155 } 156 // 29-Dec-2014, tatu: As per [databind#299], may also just let unresolved refs be... 157 if (!isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)) { 158 return; 159 } 160 UnresolvedForwardReference exception = null; 161 for (Entry<IdKey,ReadableObjectId> entry : _objectIds.entrySet()) { 162 ReadableObjectId roid = entry.getValue(); 163 if (!roid.hasReferringProperties()) { 164 continue; 165 } 166 // as per [databind#675], allow resolution at this point 167 if (tryToResolveUnresolvedObjectId(roid)) { 168 continue; 169 } 170 if (exception == null) { 171 exception = new UnresolvedForwardReference(getParser(), "Unresolved forward references for: "); 172 } 173 Object key = roid.getKey().key; 174 for (Iterator<Referring> iterator = roid.referringProperties(); iterator.hasNext(); ) { 175 Referring referring = iterator.next(); 176 exception.addUnresolvedId(key, referring.getBeanType(), referring.getLocation()); 177 } 178 } 179 if (exception != null) { 180 throw exception; 181 } 182 } 183 184 /** 185 * Overridable helper method called to try to resolve otherwise unresolvable {@link ReadableObjectId}; 186 * and if this succeeds, return <code>true</code> to indicate problem has been resolved in 187 * some way, so that caller can avoid reporting it as an error. 188 *<p> 189 * Default implementation simply calls {@link ReadableObjectId#tryToResolveUnresolved} and 190 * returns whatever it returns. 191 * 192 * @since 2.6 193 */ tryToResolveUnresolvedObjectId(ReadableObjectId roid)194 protected boolean tryToResolveUnresolvedObjectId(ReadableObjectId roid) 195 { 196 return roid.tryToResolveUnresolved(this); 197 } 198 199 /* 200 /********************************************************** 201 /* Abstract methods impls, other factory methods 202 /********************************************************** 203 */ 204 205 @SuppressWarnings("unchecked") 206 @Override deserializerInstance(Annotated ann, Object deserDef)207 public JsonDeserializer<Object> deserializerInstance(Annotated ann, Object deserDef) 208 throws JsonMappingException 209 { 210 if (deserDef == null) { 211 return null; 212 } 213 JsonDeserializer<?> deser; 214 215 if (deserDef instanceof JsonDeserializer) { 216 deser = (JsonDeserializer<?>) deserDef; 217 } else { 218 // Alas, there's no way to force return type of "either class 219 // X or Y" -- need to throw an exception after the fact 220 if (!(deserDef instanceof Class)) { 221 throw new IllegalStateException("AnnotationIntrospector returned deserializer definition of type "+deserDef.getClass().getName()+"; expected type JsonDeserializer or Class<JsonDeserializer> instead"); 222 } 223 Class<?> deserClass = (Class<?>)deserDef; 224 // there are some known "no class" markers to consider too: 225 if (deserClass == JsonDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) { 226 return null; 227 } 228 if (!JsonDeserializer.class.isAssignableFrom(deserClass)) { 229 throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName()+"; expected Class<JsonDeserializer>"); 230 } 231 HandlerInstantiator hi = _config.getHandlerInstantiator(); 232 deser = (hi == null) ? null : hi.deserializerInstance(_config, ann, deserClass); 233 if (deser == null) { 234 deser = (JsonDeserializer<?>) ClassUtil.createInstance(deserClass, 235 _config.canOverrideAccessModifiers()); 236 } 237 } 238 // First: need to resolve 239 if (deser instanceof ResolvableDeserializer) { 240 ((ResolvableDeserializer) deser).resolve(this); 241 } 242 return (JsonDeserializer<Object>) deser; 243 } 244 245 @Override keyDeserializerInstance(Annotated ann, Object deserDef)246 public final KeyDeserializer keyDeserializerInstance(Annotated ann, Object deserDef) 247 throws JsonMappingException 248 { 249 if (deserDef == null) { 250 return null; 251 } 252 253 KeyDeserializer deser; 254 255 if (deserDef instanceof KeyDeserializer) { 256 deser = (KeyDeserializer) deserDef; 257 } else { 258 if (!(deserDef instanceof Class)) { 259 throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type " 260 +deserDef.getClass().getName() 261 +"; expected type KeyDeserializer or Class<KeyDeserializer> instead"); 262 } 263 Class<?> deserClass = (Class<?>)deserDef; 264 // there are some known "no class" markers to consider too: 265 if (deserClass == KeyDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) { 266 return null; 267 } 268 if (!KeyDeserializer.class.isAssignableFrom(deserClass)) { 269 throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName() 270 +"; expected Class<KeyDeserializer>"); 271 } 272 HandlerInstantiator hi = _config.getHandlerInstantiator(); 273 deser = (hi == null) ? null : hi.keyDeserializerInstance(_config, ann, deserClass); 274 if (deser == null) { 275 deser = (KeyDeserializer) ClassUtil.createInstance(deserClass, 276 _config.canOverrideAccessModifiers()); 277 } 278 } 279 // First: need to resolve 280 if (deser instanceof ResolvableDeserializer) { 281 ((ResolvableDeserializer) deser).resolve(this); 282 } 283 return deser; 284 } 285 286 /* 287 /********************************************************** 288 /* Extended API, life-cycle 289 /********************************************************** 290 */ 291 292 /** 293 * Fluent factory method used for constructing a blueprint instance 294 * with different factory 295 */ with(DeserializerFactory factory)296 public abstract DefaultDeserializationContext with(DeserializerFactory factory); 297 298 /** 299 * Method called to create actual usable per-deserialization 300 * context instance. 301 */ createInstance( DeserializationConfig config, JsonParser p, InjectableValues values)302 public abstract DefaultDeserializationContext createInstance( 303 DeserializationConfig config, JsonParser p, InjectableValues values); 304 createDummyInstance( DeserializationConfig config)305 public abstract DefaultDeserializationContext createDummyInstance( 306 DeserializationConfig config); 307 308 /* 309 /********************************************************** 310 /* Extended API, read methods 311 /********************************************************** 312 */ 313 readRootValue(JsonParser p, JavaType valueType, JsonDeserializer<Object> deser, Object valueToUpdate)314 public Object readRootValue(JsonParser p, JavaType valueType, 315 JsonDeserializer<Object> deser, Object valueToUpdate) 316 throws IOException 317 { 318 if (_config.useRootWrapping()) { 319 return _unwrapAndDeserialize(p, valueType, deser, valueToUpdate); 320 } 321 if (valueToUpdate == null) { 322 return deser.deserialize(p, this); 323 } 324 return deser.deserialize(p, this, valueToUpdate); 325 } 326 _unwrapAndDeserialize(JsonParser p, JavaType rootType, JsonDeserializer<Object> deser, Object valueToUpdate)327 protected Object _unwrapAndDeserialize(JsonParser p, 328 JavaType rootType, JsonDeserializer<Object> deser, 329 Object valueToUpdate) 330 throws IOException 331 { 332 PropertyName expRootName = _config.findRootName(rootType); 333 // 12-Jun-2015, tatu: Should try to support namespaces etc but... 334 String expSimpleName = expRootName.getSimpleName(); 335 if (p.currentToken() != JsonToken.START_OBJECT) { 336 reportWrongTokenException(rootType, JsonToken.START_OBJECT, 337 "Current token not START_OBJECT (needed to unwrap root name '%s'), but %s", 338 expSimpleName, p.currentToken()); 339 } 340 if (p.nextToken() != JsonToken.FIELD_NAME) { 341 reportWrongTokenException(rootType, JsonToken.FIELD_NAME, 342 "Current token not FIELD_NAME (to contain expected root name '%s'), but %s", 343 expSimpleName, p.currentToken()); 344 } 345 String actualName = p.currentName(); 346 if (!expSimpleName.equals(actualName)) { 347 reportPropertyInputMismatch(rootType, actualName, 348 "Root name '%s' does not match expected ('%s') for type %s", 349 actualName, expSimpleName, rootType); 350 } 351 // ok, then move to value itself.... 352 p.nextToken(); 353 final Object result; 354 if (valueToUpdate == null) { 355 result = deser.deserialize(p, this); 356 } else { 357 result = deser.deserialize(p, this, valueToUpdate); 358 } 359 // and last, verify that we now get matching END_OBJECT 360 if (p.nextToken() != JsonToken.END_OBJECT) { 361 reportWrongTokenException(rootType, JsonToken.END_OBJECT, 362 "Current token not END_OBJECT (to match wrapper object with root name '%s'), but %s", 363 expSimpleName, p.currentToken()); 364 } 365 return result; 366 } 367 368 /* 369 /********************************************************** 370 /* And then the concrete implementation class 371 /********************************************************** 372 */ 373 374 /** 375 * Actual full concrete implementation 376 */ 377 public final static class Impl extends DefaultDeserializationContext 378 { 379 private static final long serialVersionUID = 1L; 380 381 /** 382 * Default constructor for a blueprint object, which will use the standard 383 * {@link DeserializerCache}, given factory. 384 */ Impl(DeserializerFactory df)385 public Impl(DeserializerFactory df) { 386 super(df, null); 387 } 388 Impl(Impl src, DeserializationConfig config, JsonParser p, InjectableValues values)389 private Impl(Impl src, 390 DeserializationConfig config, JsonParser p, InjectableValues values) { 391 super(src, config, p, values); 392 } 393 Impl(Impl src)394 private Impl(Impl src) { super(src); } 395 Impl(Impl src, DeserializerFactory factory)396 private Impl(Impl src, DeserializerFactory factory) { 397 super(src, factory); 398 } 399 Impl(Impl src, DeserializationConfig config)400 private Impl(Impl src, DeserializationConfig config) { 401 super(src, config); 402 } 403 404 @Override copy()405 public DefaultDeserializationContext copy() { 406 ClassUtil.verifyMustOverride(Impl.class, this, "copy"); 407 return new Impl(this); 408 } 409 410 @Override createInstance(DeserializationConfig config, JsonParser p, InjectableValues values)411 public DefaultDeserializationContext createInstance(DeserializationConfig config, 412 JsonParser p, InjectableValues values) { 413 return new Impl(this, config, p, values); 414 } 415 416 @Override createDummyInstance(DeserializationConfig config)417 public DefaultDeserializationContext createDummyInstance(DeserializationConfig config) { 418 // need to be careful to create "real", not blue-print, instance 419 return new Impl(this, config); 420 } 421 422 @Override with(DeserializerFactory factory)423 public DefaultDeserializationContext with(DeserializerFactory factory) { 424 return new Impl(this, factory); 425 } 426 } 427 } 428