• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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