1 package com.fasterxml.jackson.databind.deser;
2
3 import java.util.*;
4 import java.util.Map.Entry;
5
6 import com.fasterxml.jackson.annotation.ObjectIdGenerator;
7 import com.fasterxml.jackson.annotation.ObjectIdResolver;
8 import com.fasterxml.jackson.annotation.ObjectIdGenerator.IdKey;
9
10 import com.fasterxml.jackson.core.JsonParser;
11
12 import com.fasterxml.jackson.databind.*;
13 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator;
14 import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId;
15 import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring;
16 import com.fasterxml.jackson.databind.introspect.Annotated;
17 import com.fasterxml.jackson.databind.util.ClassUtil;
18
19 /**
20  * Complete {@link DeserializationContext} implementation that adds
21  * extended API for {@link ObjectMapper} (and {@link ObjectReader})
22  * to call, as well as implements certain parts that base class
23  * has left abstract.
24  * The remaining abstract methods ({@link #createInstance}, {@link #with})
25  * are left so that custom implementations will properly implement them
26  * to return intended subtype.
27  */

28 public abstract class DefaultDeserializationContext
29     extends DeserializationContext
30     implements java.io.Serializable // since 2.1
31 {
32     private static final long serialVersionUID = 1L;
33
34     protected transient LinkedHashMap<ObjectIdGenerator.IdKey, ReadableObjectId> _objectIds;
35
36     private List<ObjectIdResolver> _objectIdResolvers;
37
38     /**
39      * Constructor that will pass specified deserializer factory and
40      * cache: cache may be null (in which case default implementation
41      * will be used), factory cannot be null
42      */

43     protected DefaultDeserializationContext(DeserializerFactory df, DeserializerCache cache) {
44         super(df, cache);
45     }
46     
47     protected DefaultDeserializationContext(DefaultDeserializationContext src,
48             DeserializationConfig config, JsonParser jp, InjectableValues values) {
49         super(src, config, jp, values);
50     }
51
52     protected DefaultDeserializationContext(DefaultDeserializationContext src,
53             DeserializerFactory factory) {
54         super(src, factory);
55     }
56
57     /**
58      * @since 2.4.4
59      */

60     protected DefaultDeserializationContext(DefaultDeserializationContext src) {
61         super(src);
62     }
63     
64     /**
65      * Method needed to ensure that {@link ObjectMapper#copy} will work
66      * properly; specifically, that caches are cleared, but settings
67      * will otherwise remain identical; and that no sharing of state
68      * occurs.
69      * 
70      * @since 2.4.4
71      */

72     public DefaultDeserializationContext copy() {
73         throw new IllegalStateException("DefaultDeserializationContext sub-class not overriding copy()");
74     }
75
76     /*
77     /**********************************************************
78     /* Abstract methods impls, Object Id
79     /**********************************************************
80      */

81
82     @Override
83     public ReadableObjectId findObjectId(Object id, ObjectIdGenerator<?> gen, ObjectIdResolver resolverType)
84     {
85         /* 02-Apr-2015, tatu: As per [databind#742] should allow 'null', similar to how
86          *   missing id already works.
87          */

88         if (id == null) {
89             return null;
90         }
91
92         final ObjectIdGenerator.IdKey key = gen.key(id);
93
94         if (_objectIds == null) {
95             _objectIds = new LinkedHashMap<ObjectIdGenerator.IdKey,ReadableObjectId>();
96         } else {
97             ReadableObjectId entry = _objectIds.get(key);
98             if (entry != null) {
99                 return entry;
100             }
101         }
102
103         // Not seen yet, must create entry and configure resolver.
104         ObjectIdResolver resolver = null;
105
106         if (_objectIdResolvers == null) {
107             _objectIdResolvers = new ArrayList<ObjectIdResolver>(8);
108         } else {
109             for (ObjectIdResolver res : _objectIdResolvers) {
110                 if (res.canUseFor(resolverType)) {
111                     resolver = res;
112                     break;
113                 }
114             }
115         }
116
117         if (resolver == null) {
118             resolver = resolverType.newForDeserialization(this);
119             _objectIdResolvers.add(resolver);
120         }
121
122         ReadableObjectId entry = createReadableObjectId(key);
123         entry.setResolver(resolver);
124         _objectIds.put(key, entry);
125         return entry;
126     }
127
128     /**
129      * Overridable factory method to create a new instance of ReadableObjectId or its
130      * subclass. It is meant to be overridden when custom ReadableObjectId is
131      * needed for {@link #tryToResolveUnresolvedObjectId}.
132      * Default implementation simply constructs default {@link ReadableObjectId} with
133      * given <code>key</code>.
134      * 
135      * @param key The key to associate with the new ReadableObjectId
136      * @return New ReadableObjectId instance
137      *
138      * @since 2.7
139      */

140     protected ReadableObjectId createReadableObjectId(IdKey key) {
141         return new ReadableObjectId(key);
142     }
143
144     @Override
145     public void checkUnresolvedObjectId() throws UnresolvedForwardReference
146     {
147         if (_objectIds == null) {
148             return;
149         }
150         // 29-Dec-2014, tatu: As per [databind#299], may also just let unresolved refs be...
151         if (!isEnabled(DeserializationFeature.FAIL_ON_UNRESOLVED_OBJECT_IDS)) {
152             return;
153         }
154         UnresolvedForwardReference exception = null;
155         for (Entry<IdKey,ReadableObjectId> entry : _objectIds.entrySet()) {
156             ReadableObjectId roid = entry.getValue();
157             if (!roid.hasReferringProperties()) {
158                 continue;
159             }
160             // as per [databind#675], allow resolution at this point
161             if (tryToResolveUnresolvedObjectId(roid)) {
162                 continue;
163             }
164             if (exception == null) {
165                 exception = new UnresolvedForwardReference(getParser(), "Unresolved forward references for: ");
166             }
167             Object key = roid.getKey().key;
168             for (Iterator<Referring> iterator = roid.referringProperties(); iterator.hasNext(); ) {
169                 Referring referring = iterator.next();
170                 exception.addUnresolvedId(key, referring.getBeanType(), referring.getLocation());
171             }
172         }
173         if (exception != null) {
174             throw exception;
175         }
176     }
177
178     /**
179      * Overridable helper method called to try to resolve otherwise unresolvable {@link ReadableObjectId};
180      * and if this succeeds, return <code>true</code> to indicate problem has been resolved in
181      * some way, so that caller can avoid reporting it as an error.
182      *<p>
183      * Default implementation simply calls {@link ReadableObjectId#tryToResolveUnresolved} and
184      * returns whatever it returns.
185      *
186      * @since 2.6
187      */

188     protected boolean tryToResolveUnresolvedObjectId(ReadableObjectId roid)
189     {
190         return roid.tryToResolveUnresolved(this);
191     }
192     
193     /*
194     /**********************************************************
195     /* Abstract methods impls, other factory methods
196     /**********************************************************
197      */

198     
199     @SuppressWarnings("unchecked")
200     @Override
201     public JsonDeserializer<Object> deserializerInstance(Annotated ann, Object deserDef)
202         throws JsonMappingException
203     {
204         if (deserDef == null) {
205             return null;
206         }
207         JsonDeserializer<?> deser;
208         
209         if (deserDef instanceof JsonDeserializer) {
210             deser = (JsonDeserializer<?>) deserDef;
211         } else {
212             /* Alas, there's no way to force return type of "either class
213              * X or Y" -- need to throw an exception after the fact
214              */

215             if (!(deserDef instanceof Class)) {
216                 throw new IllegalStateException("AnnotationIntrospector returned deserializer definition of type "+deserDef.getClass().getName()+"; expected type JsonDeserializer or Class<JsonDeserializer> instead");
217             }
218             Class<?> deserClass = (Class<?>)deserDef;
219             // there are some known "no class" markers to consider too:
220             if (deserClass == JsonDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) {
221                 return null;
222             }
223             if (!JsonDeserializer.class.isAssignableFrom(deserClass)) {
224                 throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName()+"; expected Class<JsonDeserializer>");
225             }
226             HandlerInstantiator hi = _config.getHandlerInstantiator();
227             deser = (hi == null) ? null : hi.deserializerInstance(_config, ann, deserClass);
228             if (deser == null) {
229                 deser = (JsonDeserializer<?>) ClassUtil.createInstance(deserClass,
230                         _config.canOverrideAccessModifiers());
231             }
232         }
233         // First: need to resolve
234         if (deser instanceof ResolvableDeserializer) {
235             ((ResolvableDeserializer) deser).resolve(this);
236         }
237         return (JsonDeserializer<Object>) deser;
238     }
239
240     @Override
241     public final KeyDeserializer keyDeserializerInstance(Annotated ann, Object deserDef)
242         throws JsonMappingException
243     {
244         if (deserDef == null) {
245             return null;
246         }
247
248         KeyDeserializer deser;
249         
250         if (deserDef instanceof KeyDeserializer) {
251             deser = (KeyDeserializer) deserDef;
252         } else {
253             if (!(deserDef instanceof Class)) {
254                 throw new IllegalStateException("AnnotationIntrospector returned key deserializer definition of type "
255                         +deserDef.getClass().getName()
256                         +"; expected type KeyDeserializer or Class<KeyDeserializer> instead");
257             }
258             Class<?> deserClass = (Class<?>)deserDef;
259             // there are some known "no class" markers to consider too:
260             if (deserClass == KeyDeserializer.None.class || ClassUtil.isBogusClass(deserClass)) {
261                 return null;
262             }
263             if (!KeyDeserializer.class.isAssignableFrom(deserClass)) {
264                 throw new IllegalStateException("AnnotationIntrospector returned Class "+deserClass.getName()
265                         +"; expected Class<KeyDeserializer>");
266             }
267             HandlerInstantiator hi = _config.getHandlerInstantiator();
268             deser = (hi == null) ? null : hi.keyDeserializerInstance(_config, ann, deserClass);
269             if (deser == null) {
270                 deser = (KeyDeserializer) ClassUtil.createInstance(deserClass,
271                         _config.canOverrideAccessModifiers());
272             }
273         }
274         // First: need to resolve
275         if (deser instanceof ResolvableDeserializer) {
276             ((ResolvableDeserializer) deser).resolve(this);
277         }
278         return deser;
279     }
280
281     /*
282     /**********************************************************
283     /* Extended API
284     /**********************************************************
285      */

286
287     /**
288      * Fluent factory method used for constructing a blueprint instance
289      * with different factory
290      */

291     public abstract DefaultDeserializationContext with(DeserializerFactory factory);
292     
293     /**
294      * Method called to create actual usable per-deserialization
295      * context instance.
296      */

297     public abstract DefaultDeserializationContext createInstance(
298             DeserializationConfig config, JsonParser jp, InjectableValues values);
299     
300     /*
301     /**********************************************************
302     /* And then the concrete implementation class
303     /**********************************************************
304      */

305
306     /**
307      * Actual full concrete implementation
308      */

309     public final static class Impl extends DefaultDeserializationContext
310     {
311         private static final long serialVersionUID = 1L;
312
313         /**
314          * Default constructor for a blueprint object, which will use the standard
315          * {@link DeserializerCache}, given factory.
316          */

317         public Impl(DeserializerFactory df) {
318             super(df, null);
319         }
320
321         protected Impl(Impl src,
322                 DeserializationConfig config, JsonParser jp, InjectableValues values) {
323             super(src, config, jp, values);
324         }
325
326         protected Impl(Impl src) { super(src); }
327         
328         protected Impl(Impl src, DeserializerFactory factory) {
329             super(src, factory);
330         }
331
332         @Override
333         public DefaultDeserializationContext copy() {
334             ClassUtil.verifyMustOverride(Impl.classthis"copy");
335            return new Impl(this);
336         }
337         
338         @Override
339         public DefaultDeserializationContext createInstance(DeserializationConfig config,
340                 JsonParser p, InjectableValues values) {
341             return new Impl(this, config, p, values);
342         }
343
344         @Override
345         public DefaultDeserializationContext with(DeserializerFactory factory) {
346             return new Impl(this, factory);
347         }        
348     }
349 }
350