1 package com.fasterxml.jackson.databind.deser;
2
3 import java.io.IOException;
4 import java.lang.annotation.Annotation;
5
6 import com.fasterxml.jackson.annotation.JacksonInject;
7 import com.fasterxml.jackson.core.JsonParser;
8
9 import com.fasterxml.jackson.databind.*;
10 import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
11 import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
12 import com.fasterxml.jackson.databind.introspect.AnnotatedParameter;
13 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
14 import com.fasterxml.jackson.databind.util.Annotations;
15 import com.fasterxml.jackson.databind.util.ClassUtil;
16
17 /**
18  * This concrete sub-class implements property that is passed
19  * via Creator (constructor or static factory method).
20  * It is not a full-featured implementation in that its set method
21  * should usually not be called for primary mutation -- instead, value must separately passed --
22  * but some aspects are still needed (specifically, injection).
23  *<p>
24  * Note on injectable values: unlike with other mutators, where
25  * deserializer and injecting are separate, here we treat the two as related
26  * things. This is necessary to add proper priority, as well as to simplify
27  * coordination.
28  */

29 public class CreatorProperty
30     extends SettableBeanProperty
31 {
32     private static final long serialVersionUID = 1L;
33
34     /**
35      * Placeholder that represents constructor parameter, when it is created
36      * from actual constructor.
37      * May be null when a synthetic instance is created.
38      */

39     protected final AnnotatedParameter _annotated;
40
41     /**
42      * Id of value to inject, if value injection should be used for this parameter
43      * (in addition to, or instead of, regular deserialization).
44      *
45      * @since 2.11
46      */

47     protected final JacksonInject.Value _injectableValue;
48
49     /**
50      * In special cases, when implementing "updateValue", we cannot use
51      * constructors or factory methods, but have to fall back on using a
52      * setter (or mutable field property). If so, this refers to that fallback
53      * accessor.
54      *<p>
55      * Mutable only to allow setting after construction, but must be strictly
56      * set before any use.
57      * 
58      * @since 2.3
59      */

60     protected SettableBeanProperty _fallbackSetter;
61
62     /**
63      * @since 2.1
64      */

65     protected final int _creatorIndex;
66
67     /**
68      * Marker flag that may have to be set during construction, to indicate that
69      * although property may have been constructed and added as a placeholder,
70      * it represents something that should be ignored during deserialization.
71      * This mostly concerns Creator properties which may not be easily deleted
72      * during processing.
73      *
74      * @since 2.9.4
75      */

76     protected boolean _ignorable;
77
78     /**
79      * @since 2.11
80      */

81     protected CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName,
82             TypeDeserializer typeDeser,
83             Annotations contextAnnotations, AnnotatedParameter param,
84             int index, JacksonInject.Value injectable,
85             PropertyMetadata metadata)
86     {
87         super(name, type, wrapperName, typeDeser, contextAnnotations, metadata);
88         _annotated = param;
89         _creatorIndex = index;
90         _injectableValue = injectable;
91         _fallbackSetter = null;
92     }
93
94     /**
95      * @deprecated Since 2.11 use factory method instead
96      */

97     @Deprecated // since 2.11
98     public CreatorProperty(PropertyName name, JavaType type, PropertyName wrapperName,
99             TypeDeserializer typeDeser,
100             Annotations contextAnnotations, AnnotatedParameter param,
101             int index, Object injectableValueId,
102             PropertyMetadata metadata)
103     {
104         this(name, type, wrapperName, typeDeser, contextAnnotations, param, index,
105                 (injectableValueId == null) ? null
106                         : JacksonInject.Value.construct(injectableValueId, null),
107                 metadata);
108     }
109
110     /**
111      * Factory method for creating {@link CreatorProperty} instances
112      *
113      * @param name Name of the logical property
114      * @param type Type of the property, used to find deserializer
115      * @param wrapperName Possible wrapper to use for logical property, if any
116      * @param typeDeser Type deserializer to use for handling polymorphic type
117      *    information, if one is needed
118      * @param contextAnnotations Contextual annotations (usually by class that
119      *    declares creator [constructor, factory method] that includes
120      *    this property)
121      * @param param Representation of property, constructor or factory
122      *    method parameter; used for accessing annotations of the property
123      * @param injectable Information about injectable value, if any
124      * @param index Index of this property within creator invocation
125      * 
126      * @since 2.11
127      */

128     public static CreatorProperty construct(PropertyName name, JavaType type, PropertyName wrapperName,
129             TypeDeserializer typeDeser,
130             Annotations contextAnnotations, AnnotatedParameter param,
131             int index, JacksonInject.Value injectable,
132             PropertyMetadata metadata)
133     {
134         return new CreatorProperty(name, type, wrapperName, typeDeser, contextAnnotations,
135                 param, index, injectable, metadata);
136     }
137     
138     /**
139      * @since 2.3
140      */

141     protected CreatorProperty(CreatorProperty src, PropertyName newName) {
142         super(src, newName);
143         _annotated = src._annotated;
144         _injectableValue = src._injectableValue;
145         _fallbackSetter = src._fallbackSetter;
146         _creatorIndex = src._creatorIndex;
147         _ignorable = src._ignorable;
148     }
149
150     protected CreatorProperty(CreatorProperty src, JsonDeserializer<?> deser,
151             NullValueProvider nva) {
152         super(src, deser, nva);
153         _annotated = src._annotated;
154         _injectableValue = src._injectableValue;
155         _fallbackSetter = src._fallbackSetter;
156         _creatorIndex = src._creatorIndex;
157         _ignorable = src._ignorable;
158     }
159
160     @Override
161     public SettableBeanProperty withName(PropertyName newName) {
162         return new CreatorProperty(this, newName);
163     }
164     
165     @Override
166     public SettableBeanProperty withValueDeserializer(JsonDeserializer<?> deser) {
167         if (_valueDeserializer == deser) {
168             return this;
169         }
170         // 07-May-2019, tatu: As per [databind#2303], must keep VD/NVP in-sync if they were
171         NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider;
172         return new CreatorProperty(this, deser, nvp);
173     }
174
175     @Override
176     public SettableBeanProperty withNullProvider(NullValueProvider nva) {
177         return new CreatorProperty(this, _valueDeserializer, nva);
178     }
179     
180     @Override
181     public void fixAccess(DeserializationConfig config) {
182         if (_fallbackSetter != null) {
183             _fallbackSetter.fixAccess(config);
184         }
185     }
186
187     /**
188      * NOTE: one exception to immutability, due to problems with CreatorProperty instances
189      * being shared between Bean, separate PropertyBasedCreator
190      * 
191      * @since 2.6
192      */

193     public void setFallbackSetter(SettableBeanProperty fallbackSetter) {
194         _fallbackSetter = fallbackSetter;
195     }
196
197     @Override
198     public void markAsIgnorable() {
199         _ignorable = true;
200     }
201
202     @Override
203     public boolean isIgnorable() {
204         return _ignorable;
205     }
206
207     /*
208     /**********************************************************
209     /* Injection support
210     /**********************************************************
211      */

212
213     // 14-Apr-2020, tatu: Does not appear to be used so deprecated in 2.11.0,
214     //    to be removed from 2.12.0
215
216     // Method that can be called to locate value to be injected for this
217     // property, if it is configured for this.
218     @Deprecated // remove from 2.12
219     public Object findInjectableValue(DeserializationContext context, Object beanInstance)
220         throws JsonMappingException
221     {
222         if (_injectableValue == null) {
223             context.reportBadDefinition(ClassUtil.classOf(beanInstance),
224                     String.format("Property '%s' (type %s) has no injectable value id configured",
225                     getName(), getClass().getName()));
226         }
227         return context.findInjectableValue(_injectableValue.getId(), this, beanInstance);
228     }
229
230     // 14-Apr-2020, tatu: Does not appear to be used so deprecated in 2.11.0,
231     //    to be removed from 2.12.0
232
233     // Method to find value to inject, and inject it to this property.
234     @Deprecated // remove from 2.12
235     public void inject(DeserializationContext context, Object beanInstance) throws IOException
236     {
237         set(beanInstance, findInjectableValue(context, beanInstance));
238     }
239
240     /*
241     /**********************************************************
242     /* BeanProperty impl
243     /**********************************************************
244      */

245     
246     @Override
247     public <A extends Annotation> A getAnnotation(Class<A> acls) {
248         if (_annotated == null) {
249             return null;
250         }
251         return _annotated.getAnnotation(acls);
252     }
253
254     @Override public AnnotatedMember getMember() {  return _annotated; }
255
256     @Override public int getCreatorIndex() {
257         return _creatorIndex;
258     }
259
260     /*
261     /**********************************************************
262     /* Overridden methods, SettableBeanProperty
263     /**********************************************************
264      */

265
266     @Override
267     public void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
268             Object instance) throws IOException
269     {
270         _verifySetter();
271         _fallbackSetter.set(instance, deserialize(p, ctxt));
272     }
273
274     @Override
275     public Object deserializeSetAndReturn(JsonParser p,
276             DeserializationContext ctxt, Object instance) throws IOException
277     {
278         _verifySetter();
279         return _fallbackSetter.setAndReturn(instance, deserialize(p, ctxt));
280     }
281     
282     @Override
283     public void set(Object instance, Object value) throws IOException
284     {
285         _verifySetter();
286         _fallbackSetter.set(instance, value);
287     }
288
289     @Override
290     public Object setAndReturn(Object instance, Object value) throws IOException
291     {
292         _verifySetter();
293         return _fallbackSetter.setAndReturn(instance, value);
294     }
295
296     @Override
297     public PropertyMetadata getMetadata() {
298         // 03-Jun-2019, tatu: Added as per [databind#2280] to support merge.
299         //   Not 100% sure why it would be needed (or fixes things) but... appears to.
300         //   Need to understand better in future as it seems like it should probably be
301         //   linked earlier during construction or something.
302         // 22-Sep-2019, tatu: Was hoping [databind#2458] fixed this, too, but no such luck
303         PropertyMetadata md = super.getMetadata();
304         if (_fallbackSetter != null) {
305             return md.withMergeInfo(_fallbackSetter.getMetadata().getMergeInfo());
306         }
307         return md;
308     }
309
310     // Perhaps counter-intuitively, ONLY creator properties return non-null id
311     @Override
312     public Object getInjectableValueId() {
313         return (_injectableValue == null) ? null : _injectableValue.getId();
314     }
315
316     @Override
317     public boolean isInjectionOnly() {
318         return (_injectableValue != null) && !_injectableValue.willUseInput(true);
319     }
320
321     //  public boolean isInjectionOnly() { return false; }
322
323     /*
324     /**********************************************************
325     /* Overridden methods, other
326     /**********************************************************
327      */

328     
329     @Override
330     public String toString() { return "[creator property, name '"+getName()+"'; inject id '"+getInjectableValueId()+"']"; }
331
332     /*
333     /**********************************************************
334     /* Internal helper methods
335     /**********************************************************
336      */

337
338     // since 2.9
339     private final void _verifySetter() throws IOException {
340         if (_fallbackSetter == null) {
341             _reportMissingSetter(nullnull);
342         }
343     }
344
345     // since 2.9
346     private void _reportMissingSetter(JsonParser p, DeserializationContext ctxt) throws IOException
347     {
348         final String msg = "No fallback setter/field defined for creator property '"+getName()+"'";
349         // Hmmmh. Should we return quietly (NOP), or error?
350         // Perhaps better to throw an exception, since it's generally an error.
351         if (ctxt != null ) {
352             ctxt.reportBadDefinition(getType(), msg);
353         } else {
354             throw InvalidDefinitionException.from(p, msg, getType());
355         }
356     }
357 }
358