1 package com.fasterxml.jackson.databind.deser;
2
3 import java.io.IOException;
4 import java.util.*;
5
6 import com.fasterxml.jackson.core.*;
7 import com.fasterxml.jackson.databind.*;
8 import com.fasterxml.jackson.databind.deser.impl.*;
9 import com.fasterxml.jackson.databind.deser.impl.ReadableObjectId.Referring;
10 import com.fasterxml.jackson.databind.util.NameTransformer;
11 import com.fasterxml.jackson.databind.util.TokenBuffer;
12
13 /**
14  * Deserializer class that can deserialize instances of
15  * arbitrary bean objects, usually from JSON Object structs,
16  */

17 public class BeanDeserializer
18     extends BeanDeserializerBase
19     implements java.io.Serializable
20 {
21     /* TODOs for future versions:
22      * 
23      * For 2.9?
24      *
25      * - New method in JsonDeserializer (deserializeNext()) to allow use of more
26      *   efficient 'nextXxx()' method `JsonParser` provides.
27      *
28      * Also: need to ensure efficient impl of those methods for Smile, CBOR
29      * at least (in addition to JSON)
30      */

31
32     private static final long serialVersionUID = 1L;
33
34     /**
35      * Lazily constructed exception used as root cause if reporting problem
36      * with creator method that returns <code>null</code> (which is not allowed)
37      *
38      * @since 2.8
39      */

40     protected transient Exception _nullFromCreator;
41
42     /**
43      * State marker we need in order to avoid infinite recursion for some cases
44      * (not very clean, alas, but has to do for now)
45      *
46      * @since 2.9
47      */

48     private volatile transient NameTransformer _currentlyTransforming;
49
50     /*
51     /**********************************************************
52     /* Life-cycle, construction, initialization
53     /**********************************************************
54      */

55
56     /**
57      * Constructor used by {@link BeanDeserializerBuilder}.
58      */

59     public BeanDeserializer(BeanDeserializerBuilder builder, BeanDescription beanDesc,
60             BeanPropertyMap properties, Map<String, SettableBeanProperty> backRefs,
61             HashSet<String> ignorableProps, boolean ignoreAllUnknown,
62             boolean hasViews)
63     {
64         super(builder, beanDesc, properties, backRefs,
65                 ignorableProps, ignoreAllUnknown, hasViews);
66     }
67
68     /**
69      * Copy-constructor that can be used by sub-classes to allow
70      * copy-on-write style copying of settings of an existing instance.
71      */

72     protected BeanDeserializer(BeanDeserializerBase src) {
73         super(src, src._ignoreAllUnknown);
74     }
75
76     protected BeanDeserializer(BeanDeserializerBase src, boolean ignoreAllUnknown) {
77         super(src, ignoreAllUnknown);
78     }
79
80     protected BeanDeserializer(BeanDeserializerBase src, NameTransformer unwrapper) {
81         super(src, unwrapper);
82     }
83
84     public BeanDeserializer(BeanDeserializerBase src, ObjectIdReader oir) {
85         super(src, oir);
86     }
87
88     public BeanDeserializer(BeanDeserializerBase src, Set<String> ignorableProps) {
89         super(src, ignorableProps);
90     }
91
92     public BeanDeserializer(BeanDeserializerBase src, BeanPropertyMap props) {
93         super(src, props);
94     }
95
96     @Override
97     public JsonDeserializer<Object> unwrappingDeserializer(NameTransformer transformer)
98     {
99         // bit kludgy but we don't want to accidentally change type; sub-classes
100         // MUST override this method to support unwrapped properties...
101         if (getClass() != BeanDeserializer.class) {
102             return this;
103         }
104         // 25-Mar-2017, tatu: Not clean at all, but for [databind#383] we do need
105         //   to keep track of accidental recursion...
106         if (_currentlyTransforming == transformer) {
107             return this;
108         }
109         _currentlyTransforming = transformer;
110         try {
111             return new BeanDeserializer(this, transformer);
112         } finally { _currentlyTransforming = null; }
113     }
114
115     @Override
116     public BeanDeserializer withObjectIdReader(ObjectIdReader oir) {
117         return new BeanDeserializer(this, oir);
118     }
119
120     @Override
121     public BeanDeserializer withIgnorableProperties(Set<String> ignorableProps) {
122         return new BeanDeserializer(this, ignorableProps);
123     }
124
125     @Override
126     public BeanDeserializerBase withIgnoreAllUnknown(boolean ignoreUnknown) {
127         return new BeanDeserializer(this, ignoreUnknown);
128     }
129
130     @Override
131     public BeanDeserializerBase withBeanProperties(BeanPropertyMap props) {
132         return new BeanDeserializer(this, props);
133     }
134
135     @Override
136     protected BeanDeserializerBase asArrayDeserializer() {
137         SettableBeanProperty[] props = _beanProperties.getPropertiesInInsertionOrder();
138         return new BeanAsArrayDeserializer(this, props);
139     }
140
141     /*
142     /**********************************************************
143     /* JsonDeserializer implementation
144     /**********************************************************
145      */

146
147     /**
148      * Main deserialization method for bean-based objects (POJOs).
149      */

150     @Override
151     public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
152     {
153         // common case first
154         if (p.isExpectedStartObjectToken()) {
155             if (_vanillaProcessing) {
156                 return vanillaDeserialize(p, ctxt, p.nextToken());
157             }
158             // 23-Sep-2015, tatu: This is wrong at some many levels, but for now... it is
159             //    what it is, including "expected behavior".
160             p.nextToken();
161             if (_objectIdReader != null) {
162                 return deserializeWithObjectId(p, ctxt);
163             }
164             return deserializeFromObject(p, ctxt);
165         }
166         return _deserializeOther(p, ctxt, p.getCurrentToken());
167     }
168
169     protected final Object _deserializeOther(JsonParser p, DeserializationContext ctxt,
170             JsonToken t) throws IOException
171     {
172         // and then others, generally requiring use of @JsonCreator
173         if (t != null) {
174             switch (t) {
175             case VALUE_STRING:
176                 return deserializeFromString(p, ctxt);
177             case VALUE_NUMBER_INT:
178                 return deserializeFromNumber(p, ctxt);
179             case VALUE_NUMBER_FLOAT:
180                 return deserializeFromDouble(p, ctxt);
181             case VALUE_EMBEDDED_OBJECT:
182                 return deserializeFromEmbedded(p, ctxt);
183             case VALUE_TRUE:
184             case VALUE_FALSE:
185                 return deserializeFromBoolean(p, ctxt);
186             case VALUE_NULL:
187                 return deserializeFromNull(p, ctxt);
188             case START_ARRAY:
189                 // these only work if there's a (delegating) creator, or UNWRAP_SINGLE_ARRAY
190                 return _deserializeFromArray(p, ctxt);
191             case FIELD_NAME:
192             case END_OBJECT: // added to resolve [JACKSON-319], possible related issues
193                 if (_vanillaProcessing) {
194                     return vanillaDeserialize(p, ctxt, t);
195                 }
196                 if (_objectIdReader != null) {
197                     return deserializeWithObjectId(p, ctxt);
198                 }
199                 return deserializeFromObject(p, ctxt);
200             default:
201             }
202         }
203         return ctxt.handleUnexpectedToken(getValueType(ctxt), p);
204     }
205
206     @Deprecated // since 2.8; remove unless getting used
207     protected Object _missingToken(JsonParser p, DeserializationContext ctxt) throws IOException {
208         throw ctxt.endOfInputException(handledType());
209     }
210
211     /**
212      * Secondary deserialization method, called in cases where POJO
213      * instance is created as part of deserialization, potentially
214      * after collecting some or all of the properties to set.
215      */

216     @Override
217     public Object deserialize(JsonParser p, DeserializationContext ctxt, Object bean) throws IOException
218     {
219         // [databind#631]: Assign current value, to be accessible by custom serializers
220         p.setCurrentValue(bean);
221         if (_injectables != null) {
222             injectValues(ctxt, bean);
223         }
224         if (_unwrappedPropertyHandler != null) {
225             return deserializeWithUnwrapped(p, ctxt, bean);
226         }
227         if (_externalTypeIdHandler != null) {
228             return deserializeWithExternalTypeId(p, ctxt, bean);
229         }
230         String propName;
231
232         // 23-Mar-2010, tatu: In some cases, we start with full JSON object too...
233         if (p.isExpectedStartObjectToken()) {
234             propName = p.nextFieldName();
235             if (propName == null) {
236                 return bean;
237             }
238         } else {
239             if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
240                 propName = p.getCurrentName();
241             } else {
242                 return bean;
243             }
244         }
245         if (_needViewProcesing) {
246             Class<?> view = ctxt.getActiveView();
247             if (view != null) {
248                 return deserializeWithView(p, ctxt, bean, view);
249             }
250         }
251         do {
252             p.nextToken();
253             SettableBeanProperty prop = _beanProperties.find(propName);
254
255             if (prop != null) { // normal case
256                 try {
257                     prop.deserializeAndSet(p, ctxt, bean);
258                 } catch (Exception e) {
259                     wrapAndThrow(e, bean, propName, ctxt);
260                 }
261                 continue;
262             }
263             handleUnknownVanilla(p, ctxt, bean, propName);
264         } while ((propName = p.nextFieldName()) != null);
265         return bean;
266     }
267
268     /*
269     /**********************************************************
270     /* Concrete deserialization methods
271     /**********************************************************
272      */

273
274     /**
275      * Streamlined version that is only used when no "special"
276      * features are enabled.
277      */

278     private final Object vanillaDeserialize(JsonParser p,
279             DeserializationContext ctxt, JsonToken t)
280         throws IOException
281     {
282         final Object bean = _valueInstantiator.createUsingDefault(ctxt);
283         // [databind#631]: Assign current value, to be accessible by custom serializers
284         p.setCurrentValue(bean);
285         if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
286             String propName = p.getCurrentName();
287             do {
288                 p.nextToken();
289                 SettableBeanProperty prop = _beanProperties.find(propName);
290
291                 if (prop != null) { // normal case
292                     try {
293                         prop.deserializeAndSet(p, ctxt, bean);
294                     } catch (Exception e) {
295                         wrapAndThrow(e, bean, propName, ctxt);
296                     }
297                     continue;
298                 }
299                 handleUnknownVanilla(p, ctxt, bean, propName);
300             } while ((propName = p.nextFieldName()) != null);
301         }
302         return bean;
303     }
304
305     /**
306      * General version used when handling needs more advanced features.
307      */

308     @Override
309     public Object deserializeFromObject(JsonParser p, DeserializationContext ctxt) throws IOException
310     {
311         /* 09-Dec-2014, tatu: As per [databind#622], we need to allow Object Id references
312          *   to come in as JSON Objects as well; but for now assume they will
313          *   be simple, single-property references, which means that we can
314          *   recognize them without having to buffer anything.
315          *   Once again, if we must, we can do more complex handling with buffering,
316          *   but let's only do that if and when that becomes necessary.
317          */

318         if ((_objectIdReader != null) && _objectIdReader.maySerializeAsObject()) {
319             if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)
320                     && _objectIdReader.isValidReferencePropertyName(p.getCurrentName(), p)) {
321                 return deserializeFromObjectId(p, ctxt);
322             }
323         }
324         if (_nonStandardCreation) {
325             if (_unwrappedPropertyHandler != null) {
326                 return deserializeWithUnwrapped(p, ctxt);
327             }
328             if (_externalTypeIdHandler != null) {
329                 return deserializeWithExternalTypeId(p, ctxt);
330             }
331             Object bean = deserializeFromObjectUsingNonDefault(p, ctxt);
332             /* 27-May-2014, tatu: I don't think view processing would work
333              *   at this point, so commenting it out; but leaving in place
334              *   just in case I forgot something fundamental...
335              */

336             /*
337             if (_needViewProcesing) {
338                 Class<?> view = ctxt.getActiveView();
339                 if (view != null) {
340                     return deserializeWithView(p, ctxt, bean, view);
341                 }
342             }
343             */

344             return bean;
345         }
346         final Object bean = _valueInstantiator.createUsingDefault(ctxt);
347         // [databind#631]: Assign current value, to be accessible by custom deserializers
348         p.setCurrentValue(bean);
349         if (p.canReadObjectId()) {
350             Object id = p.getObjectId();
351             if (id != null) {
352                 _handleTypedObjectId(p, ctxt, bean, id);
353             }
354         }
355         if (_injectables != null) {
356             injectValues(ctxt, bean);
357         }
358         if (_needViewProcesing) {
359             Class<?> view = ctxt.getActiveView();
360             if (view != null) {
361                 return deserializeWithView(p, ctxt, bean, view);
362             }
363         }
364         if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
365             String propName = p.getCurrentName();
366             do {
367                 p.nextToken();
368                 SettableBeanProperty prop = _beanProperties.find(propName);
369                 if (prop != null) { // normal case
370                     try {
371                         prop.deserializeAndSet(p, ctxt, bean);
372                     } catch (Exception e) {
373                         wrapAndThrow(e, bean, propName, ctxt);
374                     }
375                     continue;
376                 }
377                 handleUnknownVanilla(p, ctxt, bean, propName);
378             } while ((propName = p.nextFieldName()) != null);
379         }
380         return bean;
381     }
382
383     /**
384      * Method called to deserialize bean using "property-based creator":
385      * this means that a non-default constructor or factory method is
386      * called, and then possibly other setters. The trick is that
387      * values for creator method need to be buffered, first; and
388      * due to non-guaranteed ordering possibly some other properties
389      * as well.
390      */

391     @Override
392     @SuppressWarnings("resource")
393     protected Object _deserializeUsingPropertyBased(final JsonParser p, final DeserializationContext ctxt)
394         throws IOException
395     {
396         final PropertyBasedCreator creator = _propertyBasedCreator;
397         PropertyValueBuffer buffer = creator.startBuilding(p, ctxt, _objectIdReader);
398         TokenBuffer unknown = null;
399         final Class<?> activeView = _needViewProcesing ? ctxt.getActiveView() : null;
400
401         JsonToken t = p.getCurrentToken();
402         List<BeanReferring> referrings = null;
403         for (; t == JsonToken.FIELD_NAME; t = p.nextToken()) {
404             String propName = p.getCurrentName();
405             p.nextToken(); // to point to value
406             // Object Id property?
407             if (buffer.readIdProperty(propName)) {
408                 continue;
409             }
410             // creator property?
411             SettableBeanProperty creatorProp = creator.findCreatorProperty(propName);
412             if (creatorProp != null) {
413                 // Last creator property to set?
414                 Object value;
415                 if ((activeView != null) && !creatorProp.visibleInView(activeView)) {
416                     p.skipChildren();
417                     continue;
418                 }
419                 value = _deserializeWithErrorWrapping(p, ctxt, creatorProp);
420                 if (buffer.assignParameter(creatorProp, value)) {
421                     p.nextToken(); // to move to following FIELD_NAME/END_OBJECT
422                     Object bean;
423                     try {
424                         bean = creator.build(ctxt, buffer);
425                     } catch (Exception e) {
426                         bean = wrapInstantiationProblem(e, ctxt);
427                     }
428                     if (bean == null) {
429                         return ctxt.handleInstantiationProblem(handledType(), null,
430                                 _creatorReturnedNullException());
431                     }
432                     // [databind#631]: Assign current value, to be accessible by custom serializers
433                     p.setCurrentValue(bean);
434
435                     //  polymorphic?
436                     if (bean.getClass() != _beanType.getRawClass()) {
437                         return handlePolymorphic(p, ctxt, bean, unknown);
438                     }
439                     if (unknown != null) { // nope, just extra unknown stuff...
440                         bean = handleUnknownProperties(ctxt, bean, unknown);
441                     }
442                     // or just clean?
443                     return deserialize(p, ctxt, bean);
444                 }
445                 continue;
446             }
447             // regular property? needs buffering
448             SettableBeanProperty prop = _beanProperties.find(propName);
449             if (prop != null) {
450                 try {
451                     buffer.bufferProperty(prop, _deserializeWithErrorWrapping(p, ctxt, prop));
452                 } catch (UnresolvedForwardReference reference) {
453                     // 14-Jun-2016, tatu: As per [databind#1261], looks like we need additional
454                     //    handling of forward references here. Not exactly sure why existing
455                     //    facilities did not cover, but this does appear to solve the problem
456                     BeanReferring referring = handleUnresolvedReference(ctxt,
457                             prop, buffer, reference);
458                     if (referrings == null) {
459                         referrings = new ArrayList<BeanReferring>();
460                     }
461                     referrings.add(referring);
462                 }
463                 continue;
464             }
465             // Things marked as ignorable should not be passed to any setter
466             if (_ignorableProps != null && _ignorableProps.contains(propName)) {
467                 handleIgnoredProperty(p, ctxt, handledType(), propName);
468                 continue;
469             }
470             // "any property"?
471             if (_anySetter != null) {
472                 try {
473                     buffer.bufferAnyProperty(_anySetter, propName, _anySetter.deserialize(p, ctxt));
474                 } catch (Exception e) {
475                     wrapAndThrow(e, _beanType.getRawClass(), propName, ctxt);
476                 }
477                 continue;
478             }
479             // Ok then, let's collect the whole field; name and value
480             if (unknown == null) {
481                 unknown = new TokenBuffer(p, ctxt);
482             }
483             unknown.writeFieldName(propName);
484             unknown.copyCurrentStructure(p);
485         }
486
487         // We hit END_OBJECT, so:
488         Object bean;
489         try {
490             bean = creator.build(ctxt, buffer);
491         } catch (Exception e) {
492             wrapInstantiationProblem(e, ctxt);
493             bean = null// never gets here
494         }
495         // 13-Apr-2020, tatu: [databind#2678] need to handle injection here
496         if (_injectables != null) {
497             injectValues(ctxt, bean);
498         }
499
500         if (referrings != null) {
501             for (BeanReferring referring : referrings) {
502                referring.setBean(bean);
503             }
504         }
505         if (unknown != null) {
506             // polymorphic?
507             if (bean.getClass() != _beanType.getRawClass()) {
508                 return handlePolymorphic(null, ctxt, bean, unknown);
509             }
510             // no, just some extra unknown properties
511             return handleUnknownProperties(ctxt, bean, unknown);
512         }
513         return bean;
514     }
515
516     /**
517      * @since 2.8
518      */

519     private BeanReferring handleUnresolvedReference(DeserializationContext ctxt,
520             SettableBeanProperty prop, PropertyValueBuffer buffer,
521             UnresolvedForwardReference reference)
522         throws JsonMappingException
523     {
524         BeanReferring referring = new BeanReferring(ctxt, reference,
525                 prop.getType(), buffer, prop);
526         reference.getRoid().appendReferring(referring);
527         return referring;
528     }
529
530     protected final Object _deserializeWithErrorWrapping(JsonParser p,
531             DeserializationContext ctxt, SettableBeanProperty prop)
532         throws IOException
533     {
534         try {
535             return prop.deserialize(p, ctxt);
536         } catch (Exception e) {
537             wrapAndThrow(e, _beanType.getRawClass(), prop.getName(), ctxt);
538             // never gets here, unless caller declines to throw an exception
539             return null;
540         }
541     }
542
543     /**
544      * Helper method called for rare case of pointing to {@link JsonToken#VALUE_NULL}
545      * token. While this is most often an erroneous condition, there is one specific
546      * case with XML handling where polymorphic type with no properties is exposed
547      * as such, and should be handled same as empty Object.
548      *
549      * @since 2.7
550      */

551     protected Object deserializeFromNull(JsonParser p, DeserializationContext ctxt)
552         throws IOException
553     {
554         // 17-Dec-2015, tatu: Highly specialized case, mainly to support polymorphic
555         //   "empty" POJOs deserialized from XML, where empty XML tag synthesizes a
556         //   `VALUE_NULL` token.
557         if (p.requiresCustomCodec()) { // not only XML module, but mostly it...
558             @SuppressWarnings("resource")
559             TokenBuffer tb = new TokenBuffer(p, ctxt);
560             tb.writeEndObject();
561             JsonParser p2 = tb.asParser(p);
562             p2.nextToken(); // to point to END_OBJECT
563             // note: don't have ObjectId to consider at this point, so:
564             Object ob = _vanillaProcessing ? vanillaDeserialize(p2, ctxt, JsonToken.END_OBJECT)
565                     : deserializeFromObject(p2, ctxt);
566             p2.close();
567             return ob;
568         }
569         return ctxt.handleUnexpectedToken(getValueType(ctxt), p);
570     }
571
572     @Override
573     protected Object _deserializeFromArray(JsonParser p, DeserializationContext ctxt) throws IOException
574     {
575         // note: cannot call `_delegateDeserializer()` since order reversed here:
576         JsonDeserializer<Object> delegateDeser = _arrayDelegateDeserializer;
577         // fallback to non-array delegate
578         if ((delegateDeser != null) || ((delegateDeser = _delegateDeserializer) != null)) {
579             Object bean = _valueInstantiator.createUsingArrayDelegate(ctxt,
580                     delegateDeser.deserialize(p, ctxt));
581             if (_injectables != null) {
582                 injectValues(ctxt, bean);
583             }
584             return bean;
585         }
586         if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
587             JsonToken t = p.nextToken();
588             if (t == JsonToken.END_ARRAY && ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) {
589                 return null;
590             }
591             final Object value = deserialize(p, ctxt);
592             if (p.nextToken() != JsonToken.END_ARRAY) {
593                 handleMissingEndArrayForSingle(p, ctxt);
594             }
595             return value;
596         }
597         if (ctxt.isEnabled(DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT)) {
598             JsonToken t = p.nextToken();
599             if (t == JsonToken.END_ARRAY) {
600                 return null;
601             }
602             return ctxt.handleUnexpectedToken(getValueType(ctxt), JsonToken.START_ARRAY, p, null);
603         }
604         return ctxt.handleUnexpectedToken(getValueType(ctxt), p);
605     }
606
607     /*
608     /**********************************************************
609     /* Deserializing when we have to consider an active View
610     /**********************************************************
611      */

612
613     protected final Object deserializeWithView(JsonParser p, DeserializationContext ctxt,
614             Object bean, Class<?> activeView)
615         throws IOException
616     {
617         if (p.hasTokenId(JsonTokenId.ID_FIELD_NAME)) {
618             String propName = p.getCurrentName();
619             do {
620                 p.nextToken();
621                 // TODO: 06-Jan-2015, tatu: try streamlining call sequences here as well
622                 SettableBeanProperty prop = _beanProperties.find(propName);
623                 if (prop != null) {
624                     if (!prop.visibleInView(activeView)) {
625                         p.skipChildren();
626                         continue;
627                     }
628                     try {
629                         prop.deserializeAndSet(p, ctxt, bean);
630                     } catch (Exception e) {
631                         wrapAndThrow(e, bean, propName, ctxt);
632                     }
633                     continue;
634                 }
635                 handleUnknownVanilla(p, ctxt, bean, propName);
636             } while ((propName = p.nextFieldName()) != null);
637         }
638         return bean;
639     }
640     
641     /*
642     /**********************************************************
643     /* Handling for cases where we have "unwrapped" values
644     /**********************************************************
645      */

646
647     /**
648      * Method called when there are declared "unwrapped" properties
649      * which need special handling
650      */

651     @SuppressWarnings("resource")
652     protected Object deserializeWithUnwrapped(JsonParser p, DeserializationContext ctxt)
653         throws IOException
654     {
655         if (_delegateDeserializer != null) {
656             return _valueInstantiator.createUsingDelegate(ctxt, _delegateDeserializer.deserialize(p, ctxt));
657         }
658         if (_propertyBasedCreator != null) {
659             return deserializeUsingPropertyBasedWithUnwrapped(p, ctxt);
660         }
661         TokenBuffer tokens = new TokenBuffer(p, ctxt);
662         tokens.writeStartObject();
663         final Object bean = _valueInstantiator.createUsingDefault(ctxt);
664
665         // [databind#631]: Assign current value, to be accessible by custom serializers
666         p.setCurrentValue(bean);
667
668         if (_injectables != null) {
669             injectValues(ctxt, bean);
670         }
671         final Class<?> activeView = _needViewProcesing ? ctxt.getActiveView() : null;
672         String propName = p.hasTokenId(JsonTokenId.ID_FIELD_NAME) ? p.getCurrentName() : null;
673
674         for (; propName != null; propName = p.nextFieldName()) {
675             p.nextToken();
676             SettableBeanProperty prop = _beanProperties.find(propName);
677             if (prop != null) { // normal case
678                 if ((activeView != null) && !prop.visibleInView(activeView)) {
679                     p.skipChildren();
680                     continue;
681                 }
682                 try {
683                     prop.deserializeAndSet(p, ctxt, bean);
684                 } catch (Exception e) {
685                     wrapAndThrow(e, bean, propName, ctxt);
686                 }
687                 continue;
688             }
689             // Things marked as ignorable should not be passed to any setter
690             if (_ignorableProps != null && _ignorableProps.contains(propName)) {
691                 handleIgnoredProperty(p, ctxt, bean, propName);
692                 continue;
693             }
694             // 29-Nov-2016, tatu: probably should try to avoid sending content
695             //    both to any setter AND buffer... but, for now, the only thing
696             //    we can do.
697             // how about any setter? We'll get copies but...
698             if (_anySetter == null) {
699                 // but... others should be passed to unwrapped property deserializers
700                 tokens.writeFieldName(propName);
701                 tokens.copyCurrentStructure(p);
702                 continue;
703             }
704             // Need to copy to a separate buffer first
705             TokenBuffer b2 = TokenBuffer.asCopyOfValue(p);
706             tokens.writeFieldName(propName);
707             tokens.append(b2);
708             try {
709                 _anySetter.deserializeAndSet(b2.asParserOnFirstToken(), ctxt, bean, propName);
710             } catch (Exception e) {
711                 wrapAndThrow(e, bean, propName, ctxt);
712             }
713         }
714         tokens.writeEndObject();
715         _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens);
716         return bean;
717     }
718
719     @SuppressWarnings("resource")
720     protected Object deserializeWithUnwrapped(JsonParser p, DeserializationContext ctxt,
721             Object bean)
722         throws IOException
723     {
724         JsonToken t = p.getCurrentToken();
725         if (t == JsonToken.START_OBJECT) {
726             t = p.nextToken();
727         }
728         TokenBuffer tokens = new TokenBuffer(p, ctxt);
729         tokens.writeStartObject();
730         final Class<?> activeView = _needViewProcesing ? ctxt.getActiveView() : null;
731         for (; t == JsonToken.FIELD_NAME; t = p.nextToken()) {
732             String propName = p.getCurrentName();
733             SettableBeanProperty prop = _beanProperties.find(propName);
734             p.nextToken();
735             if (prop != null) { // normal case
736                 if (activeView != null && !prop.visibleInView(activeView)) {
737                     p.skipChildren();
738                     continue;
739                 }
740                 try {
741                     prop.deserializeAndSet(p, ctxt, bean);
742                 } catch (Exception e) {
743                     wrapAndThrow(e, bean, propName, ctxt);
744                 }
745                 continue;
746             }
747             if (_ignorableProps != null && _ignorableProps.contains(propName)) {
748                 handleIgnoredProperty(p, ctxt, bean, propName);
749                 continue;
750             }
751             // 29-Nov-2016, tatu: probably should try to avoid sending content
752             //    both to any setter AND buffer... but, for now, the only thing
753             //    we can do.
754             // how about any setter? We'll get copies but...
755             if (_anySetter == null) {
756                 // but... others should be passed to unwrapped property deserializers
757                 tokens.writeFieldName(propName);
758                 tokens.copyCurrentStructure(p);
759             } else {
760                 // Need to copy to a separate buffer first
761                 TokenBuffer b2 = TokenBuffer.asCopyOfValue(p);
762                 tokens.writeFieldName(propName);
763                 tokens.append(b2);
764                 try {
765                     _anySetter.deserializeAndSet(b2.asParserOnFirstToken(), ctxt, bean, propName);
766                 } catch (Exception e) {
767                     wrapAndThrow(e, bean, propName, ctxt);
768                 }
769                 continue;
770             }
771         }
772         tokens.writeEndObject();
773         _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens);
774         return bean;
775     }
776
777     @SuppressWarnings("resource")
778     protected Object deserializeUsingPropertyBasedWithUnwrapped(JsonParser p, DeserializationContext ctxt)
779         throws IOException
780     {
781         // 01-Dec-2016, tatu: Note: This IS legal to call, but only when unwrapped
782         //    value itself is NOT passed via `CreatorProperty` (which isn't supported).
783         //    Ok however to pass via setter or field.
784         
785         final PropertyBasedCreator creator = _propertyBasedCreator;
786         PropertyValueBuffer buffer = creator.startBuilding(p, ctxt, _objectIdReader);
787
788         TokenBuffer tokens = new TokenBuffer(p, ctxt);
789         tokens.writeStartObject();
790
791         JsonToken t = p.getCurrentToken();
792         for (; t == JsonToken.FIELD_NAME; t = p.nextToken()) {
793             String propName = p.getCurrentName();
794             p.nextToken(); // to point to value
795             // creator property?
796             SettableBeanProperty creatorProp = creator.findCreatorProperty(propName);
797             if (creatorProp != null) {
798                 // Last creator property to set?
799                 if (buffer.assignParameter(creatorProp,
800                         _deserializeWithErrorWrapping(p, ctxt, creatorProp))) {
801                     t = p.nextToken(); // to move to following FIELD_NAME/END_OBJECT
802                     Object bean;
803                     try {
804                         bean = creator.build(ctxt, buffer);
805                     } catch (Exception e) {
806                         bean = wrapInstantiationProblem(e, ctxt);
807                     }
808                     // [databind#631]: Assign current value, to be accessible by custom serializers
809                     p.setCurrentValue(bean);
810                     // if so, need to copy all remaining tokens into buffer
811                     while (t == JsonToken.FIELD_NAME) {
812                         // NOTE: do NOT skip name as it needs to be copied; `copyCurrentStructure` does that
813                         tokens.copyCurrentStructure(p);
814                         t = p.nextToken();
815                     }
816                     // 28-Aug-2018, tatu: Let's add sanity check here, easier to catch off-by-some
817                     //    problems if we maintain invariants
818                     if (t != JsonToken.END_OBJECT) {
819                         ctxt.reportWrongTokenException(this, JsonToken.END_OBJECT, 
820                                 "Attempted to unwrap '%s' value",
821                                 handledType().getName());
822                     }
823                     tokens.writeEndObject();
824                     if (bean.getClass() != _beanType.getRawClass()) {
825                         // !!! 08-Jul-2011, tatu: Could probably support; but for now
826                         //   it's too complicated, so bail out
827                         ctxt.reportInputMismatch(creatorProp,
828                                 "Cannot create polymorphic instances with unwrapped values");
829                         return null;
830                     }
831                     return _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens);
832                 }
833                 continue;
834             }
835             // Object Id property?
836             if (buffer.readIdProperty(propName)) {
837                 continue;
838             }
839             // regular property? needs buffering
840             SettableBeanProperty prop = _beanProperties.find(propName);
841             if (prop != null) {
842                 buffer.bufferProperty(prop, _deserializeWithErrorWrapping(p, ctxt, prop));
843                 continue;
844             }
845             // Things marked as ignorable should not be passed to any setter
846             if (_ignorableProps != null && _ignorableProps.contains(propName)) {
847                 handleIgnoredProperty(p, ctxt, handledType(), propName);
848                 continue;
849             }
850             // 29-Nov-2016, tatu: probably should try to avoid sending content
851             //    both to any setter AND buffer... but, for now, the only thing
852             //    we can do.
853             // how about any setter? We'll get copies but...
854             if (_anySetter == null) {
855                 // but... others should be passed to unwrapped property deserializers
856                 tokens.writeFieldName(propName);
857                 tokens.copyCurrentStructure(p);
858             } else {
859                 // Need to copy to a separate buffer first
860                 TokenBuffer b2 = TokenBuffer.asCopyOfValue(p);
861                 tokens.writeFieldName(propName);
862                 tokens.append(b2);
863                 try {
864                     buffer.bufferAnyProperty(_anySetter, propName,
865                             _anySetter.deserialize(b2.asParserOnFirstToken(), ctxt));
866                 } catch (Exception e) {
867                     wrapAndThrow(e, _beanType.getRawClass(), propName, ctxt);
868                 }
869                 continue;
870             }
871         }
872
873         // We hit END_OBJECT, so:
874         Object bean;
875         try {
876             bean = creator.build(ctxt, buffer);
877         } catch (Exception e) {
878             wrapInstantiationProblem(e, ctxt);
879             return null// never gets here
880         }
881         return _unwrappedPropertyHandler.processUnwrapped(p, ctxt, bean, tokens);
882     }
883
884     /*
885     /**********************************************************
886     /* Handling for cases where we have property/-ies with
887     /* external type id
888     /**********************************************************
889      */

890
891     protected Object deserializeWithExternalTypeId(JsonParser p, DeserializationContext ctxt)
892         throws IOException
893     {
894         if (_propertyBasedCreator != null) {
895             return deserializeUsingPropertyBasedWithExternalTypeId(p, ctxt);
896         }
897         if (_delegateDeserializer != null) {
898             /* 24-Nov-2015, tatu: Use of delegating creator needs to have precedence, and basically
899              *   external type id handling just has to be ignored, as they would relate to target
900              *   type and not delegate type. Whether this works as expected is another story, but
901              *   there's no other way to really mix these conflicting features.
902              */

903             return _valueInstantiator.createUsingDelegate(ctxt,
904                     _delegateDeserializer.deserialize(p, ctxt));
905         }
906
907         return deserializeWithExternalTypeId(p, ctxt, _valueInstantiator.createUsingDefault(ctxt));
908     }
909
910     protected Object deserializeWithExternalTypeId(JsonParser p, DeserializationContext ctxt,
911             Object bean)
912         throws IOException
913     {
914         final Class<?> activeView = _needViewProcesing ? ctxt.getActiveView() : null;
915         final ExternalTypeHandler ext = _externalTypeIdHandler.start();
916
917         for (JsonToken t = p.getCurrentToken(); t == JsonToken.FIELD_NAME; t = p.nextToken()) {
918             String propName = p.getCurrentName();
919             t = p.nextToken();
920             SettableBeanProperty prop = _beanProperties.find(propName);
921             if (prop != null) { // normal case
922                 // [JACKSON-831]: may have property AND be used as external type id:
923                 if (t.isScalarValue()) {
924                     ext.handleTypePropertyValue(p, ctxt, propName, bean);
925                 }
926                 if (activeView != null && !prop.visibleInView(activeView)) {
927                     p.skipChildren();
928                     continue;
929                 }
930                 try {
931                     prop.deserializeAndSet(p, ctxt, bean);
932                 } catch (Exception e) {
933                     wrapAndThrow(e, bean, propName, ctxt);
934                 }
935                 continue;
936             }
937             // ignorable things should be ignored
938             if (_ignorableProps != null && _ignorableProps.contains(propName)) {
939                 handleIgnoredProperty(p, ctxt, bean, propName);
940                 continue;
941             }
942             // but others are likely to be part of external type id thingy...
943             if (ext.handlePropertyValue(p, ctxt, propName, bean)) {
944                 continue;
945             }
946             // if not, the usual fallback handling:
947             if (_anySetter != null) {
948                 try {
949                     _anySetter.deserializeAndSet(p, ctxt, bean, propName);
950                 } catch (Exception e) {
951                     wrapAndThrow(e, bean, propName, ctxt);
952                 }
953                 continue;
954             }
955             // Unknown: let's call handler method
956             handleUnknownProperty(p, ctxt, bean, propName);
957         }
958         // and when we get this far, let's try finalizing the deal:
959         return ext.complete(p, ctxt, bean);
960     }
961
962     @SuppressWarnings("resource")
963     protected Object deserializeUsingPropertyBasedWithExternalTypeId(JsonParser p, DeserializationContext ctxt)
964         throws IOException
965     {
966         final ExternalTypeHandler ext = _externalTypeIdHandler.start();
967         final PropertyBasedCreator creator = _propertyBasedCreator;
968         PropertyValueBuffer buffer = creator.startBuilding(p, ctxt, _objectIdReader);
969
970         TokenBuffer tokens = new TokenBuffer(p, ctxt);
971         tokens.writeStartObject();
972
973         JsonToken t = p.getCurrentToken();
974         for (; t == JsonToken.FIELD_NAME; t = p.nextToken()) {
975             String propName = p.getCurrentName();
976             p.nextToken(); // to point to value
977             // creator property?
978             SettableBeanProperty creatorProp = creator.findCreatorProperty(propName);
979             if (creatorProp != null) {
980                 // first: let's check to see if this might be part of value with external type id:
981                 // 11-Sep-2015, tatu: Important; do NOT pass buffer as last arg, but null,
982                 //   since it is not the bean
983                 if (ext.handlePropertyValue(p, ctxt, propName, null)) {
984                     ;
985                 } else {
986                     // Last creator property to set?
987                     if (buffer.assignParameter(creatorProp, _deserializeWithErrorWrapping(p, ctxt, creatorProp))) {
988                         t = p.nextToken(); // to move to following FIELD_NAME/END_OBJECT
989                         Object bean;
990                         try {
991                             bean = creator.build(ctxt, buffer);
992                         } catch (Exception e) {
993                             wrapAndThrow(e, _beanType.getRawClass(), propName, ctxt);
994                             continue// never gets here
995                         }
996                         // if so, need to copy all remaining tokens into buffer
997                         while (t == JsonToken.FIELD_NAME) {
998                             p.nextToken(); // to skip name
999                             tokens.copyCurrentStructure(p);
1000                             t = p.nextToken();
1001                         }
1002                         if (bean.getClass() != _beanType.getRawClass()) {
1003                             // !!! 08-Jul-2011, tatu: Could theoretically support; but for now
1004                             //   it's too complicated, so bail out
1005                             return ctxt.reportBadDefinition(_beanType, String.format(
1006                                     "Cannot create polymorphic instances with external type ids (%s -> %s)",
1007                                     _beanType, bean.getClass()));
1008                         }
1009                         return ext.complete(p, ctxt, bean);
1010                     }
1011                 }
1012                 continue;
1013             }
1014             // Object Id property?
1015             if (buffer.readIdProperty(propName)) {
1016                 continue;
1017             }
1018             // regular property? needs buffering
1019             SettableBeanProperty prop = _beanProperties.find(propName);
1020             if (prop != null) {
1021                 buffer.bufferProperty(prop, prop.deserialize(p, ctxt));
1022                 continue;
1023             }
1024             // external type id (or property that depends on it)?
1025             if (ext.handlePropertyValue(p, ctxt, propName, null)) {
1026                 continue;
1027             }
1028             // Things marked as ignorable should not be passed to any setter
1029             if (_ignorableProps != null && _ignorableProps.contains(propName)) {
1030                 handleIgnoredProperty(p, ctxt, handledType(), propName);
1031                 continue;
1032             }
1033             // "any property"?
1034             if (_anySetter != null) {
1035                 buffer.bufferAnyProperty(_anySetter, propName,
1036                         _anySetter.deserialize(p, ctxt));
1037                 continue;
1038             }
1039             // Unknown: let's call handler method
1040             handleUnknownProperty(p, ctxt, _valueClass, propName);
1041         }
1042         tokens.writeEndObject();
1043
1044         // We hit END_OBJECT; resolve the pieces:
1045         try {
1046             return ext.complete(p, ctxt, buffer, creator);
1047         } catch (Exception e) {
1048             return wrapInstantiationProblem(e, ctxt);
1049         }
1050     }
1051
1052     /**
1053      * Helper method for getting a lazily construct exception to be reported
1054      * to {@link DeserializationContext#handleInstantiationProblem(Class, Object, Throwable)}.
1055      *
1056      * @since 2.8
1057      */

1058     protected Exception _creatorReturnedNullException() {
1059         if (_nullFromCreator == null) {
1060             _nullFromCreator = new NullPointerException("JSON Creator returned null");
1061         }
1062         return _nullFromCreator;
1063     }
1064
1065     /**
1066      * @since 2.8
1067      */

1068     static class BeanReferring extends Referring
1069     {
1070         private final DeserializationContext _context;
1071         private final SettableBeanProperty _prop;
1072         private Object _bean;
1073
1074         BeanReferring(DeserializationContext ctxt, UnresolvedForwardReference ref,
1075                 JavaType valueType, PropertyValueBuffer buffer, SettableBeanProperty prop)
1076         {
1077             super(ref, valueType);
1078             _context = ctxt;
1079             _prop = prop;
1080         }
1081
1082         public void setBean(Object bean) {
1083             _bean = bean;
1084         }
1085
1086         @Override
1087         public void handleResolvedForwardReference(Object id, Object value) throws IOException
1088         {
1089             if (_bean == null) {
1090                 _context.reportInputMismatch(_prop,
1091 "Cannot resolve ObjectId forward reference using property '%s' (of type %s): Bean not yet resolved",
1092 _prop.getName(), _prop.getDeclaringClass().getName());
1093         }
1094             _prop.set(_bean, value);
1095         }
1096     }
1097 }
1098