1 package com.fasterxml.jackson.databind.deser.impl;
2
3 import java.io.IOException;
4 import java.lang.annotation.Annotation;
5 import java.lang.reflect.Method;
6
7 import com.fasterxml.jackson.core.JsonParser;
8 import com.fasterxml.jackson.core.JsonToken;
9
10 import com.fasterxml.jackson.databind.*;
11 import com.fasterxml.jackson.databind.deser.NullValueProvider;
12 import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
13 import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
14 import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
15 import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
16 import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
17 import com.fasterxml.jackson.databind.util.Annotations;
18
19 /**
20  * This concrete sub-class implements Collection or Map property that is
21  * indirectly by getting the property value and directly modifying it.
22  */

23 public final class SetterlessProperty
24     extends SettableBeanProperty
25 {
26     private static final long serialVersionUID = 1L;
27
28     protected final AnnotatedMethod _annotated;
29
30     /**
31      * Get method for accessing property value used to access property
32      * (of Collection or Map type) to modify.
33      */

34     protected final Method _getter;
35
36     public SetterlessProperty(BeanPropertyDefinition propDef, JavaType type,
37             TypeDeserializer typeDeser, Annotations contextAnnotations, AnnotatedMethod method)
38     {
39         super(propDef, type, typeDeser, contextAnnotations);
40         _annotated = method;
41         _getter = method.getAnnotated();
42     }
43
44     protected SetterlessProperty(SetterlessProperty src, JsonDeserializer<?> deser,
45             NullValueProvider nva) {
46         super(src, deser, nva);
47         _annotated = src._annotated;
48         _getter = src._getter;
49     }
50
51     protected SetterlessProperty(SetterlessProperty src, PropertyName newName) {
52         super(src, newName);
53         _annotated = src._annotated;
54         _getter = src._getter;
55     }
56
57     @Override
58     public SettableBeanProperty withName(PropertyName newName) {
59         return new SetterlessProperty(this, newName);
60     }
61
62     @Override
63     public SettableBeanProperty withValueDeserializer(JsonDeserializer<?> deser) {
64         if (_valueDeserializer == deser) {
65             return this;
66         }
67         // 07-May-2019, tatu: As per [databind#2303], must keep VD/NVP in-sync if they were
68         NullValueProvider nvp = (_valueDeserializer == _nullProvider) ? deser : _nullProvider;
69         return new SetterlessProperty(this, deser, nvp);
70     }
71
72     @Override
73     public SettableBeanProperty withNullProvider(NullValueProvider nva) {
74         return new SetterlessProperty(this, _valueDeserializer, nva);
75     }
76
77     @Override
78     public void fixAccess(DeserializationConfig config) {
79         _annotated.fixAccess(
80                 config.isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS));
81     }
82
83     /*
84     /**********************************************************
85     /* BeanProperty impl
86     /**********************************************************
87      */

88     
89     @Override
90     public <A extends Annotation> A getAnnotation(Class<A> acls) {
91         return _annotated.getAnnotation(acls);
92     }
93
94     @Override public AnnotatedMember getMember() {  return _annotated; }
95
96     /*
97     /**********************************************************
98     /* Overridden methods
99     /**********************************************************
100      */

101     
102     @Override
103     public final void deserializeAndSet(JsonParser p, DeserializationContext ctxt,
104             Object instance) throws IOException
105     {
106         if (p.hasToken(JsonToken.VALUE_NULL)) {
107             // Hmmh. Is this a problem? We won't be setting anything, so it's
108             // equivalent of empty Collection/Map in this case
109             return;
110         }
111         // For [databind#501] fix we need to implement this but:
112         if (_valueTypeDeserializer != null) {
113             ctxt.reportBadDefinition(getType(), String.format(
114                     "Problem deserializing 'setterless' property (\"%s\"): no way to handle typed deser with setterless yet",
115                     getName()));
116 //            return _valueDeserializer.deserializeWithType(p, ctxt, _valueTypeDeserializer);
117         }
118         // Ok: then, need to fetch Collection/Map to modify:
119         Object toModify;
120         try {
121             toModify = _getter.invoke(instance, (Object[]) null);
122         } catch (Exception e) {
123             _throwAsIOE(p, e);
124             return// never gets here
125         }
126         // Note: null won't work, since we can't then inject anything in. At least
127         // that's not good in common case. However, theoretically the case where
128         // we get JSON null might be compatible. If so, implementation could be changed.
129         if (toModify == null) {
130             ctxt.reportBadDefinition(getType(), String.format(
131                     "Problem deserializing 'setterless' property '%s': get method returned null",
132                     getName()));
133         }
134         _valueDeserializer.deserialize(p, ctxt, toModify);
135     }
136
137     @Override
138     public Object deserializeSetAndReturn(JsonParser p,
139             DeserializationContext ctxt, Object instance) throws IOException
140     {
141         deserializeAndSet(p, ctxt, instance);
142         return instance;
143     }
144
145     @Override
146     public final void set(Object instance, Object value) throws IOException {
147         throw new UnsupportedOperationException("Should never call `set()` on setterless property ('"+getName()+"')");
148     }
149
150     @Override
151     public Object setAndReturn(Object instance, Object value) throws IOException
152     {
153         set(instance, value);
154         return instance;
155     }
156 }