1 package com.fasterxml.jackson.databind.deser.impl; 2 3 import java.io.IOException; 4 import java.util.BitSet; 5 6 import com.fasterxml.jackson.core.JsonParser; 7 import com.fasterxml.jackson.databind.DeserializationContext; 8 import com.fasterxml.jackson.databind.DeserializationFeature; 9 import com.fasterxml.jackson.databind.JsonDeserializer; 10 import com.fasterxml.jackson.databind.JsonMappingException; 11 import com.fasterxml.jackson.databind.deser.SettableAnyProperty; 12 import com.fasterxml.jackson.databind.deser.SettableBeanProperty; 13 import com.fasterxml.jackson.databind.introspect.AnnotatedMember; 14 15 /** 16 * Simple container used for temporarily buffering a set of 17 * <code>PropertyValue</code>s. 18 * Using during construction of beans (and Maps) that use Creators, 19 * and hence need buffering before instance (that will have properties 20 * to assign values to) is constructed. 21 */ 22 public class PropertyValueBuffer 23 { 24 /* 25 /********************************************************** 26 /* Configuration 27 /********************************************************** 28 */ 29 30 protected final JsonParser _parser; 31 protected final DeserializationContext _context; 32 33 protected final ObjectIdReader _objectIdReader; 34 35 /* 36 /********************************************************** 37 /* Accumulated properties, other stuff 38 /********************************************************** 39 */ 40 41 /** 42 * Buffer used for storing creator parameters for constructing 43 * instance. 44 */ 45 protected final Object[] _creatorParameters; 46 47 /** 48 * Number of creator parameters for which we have not yet received 49 * values. 50 */ 51 protected int _paramsNeeded; 52 53 /** 54 * Bitflag used to track parameters found from incoming data 55 * when number of parameters is 56 * less than 32 (fits in int). 57 */ 58 protected int _paramsSeen; 59 60 /** 61 * Bitflag used to track parameters found from incoming data 62 * when number of parameters is 63 * 32 or higher. 64 */ 65 protected final BitSet _paramsSeenBig; 66 67 /** 68 * If we get non-creator parameters before or between 69 * creator parameters, those need to be buffered. Buffer 70 * is just a simple linked list 71 */ 72 protected PropertyValue _buffered; 73 74 /** 75 * In case there is an Object Id property to handle, this is the value 76 * we have for it. 77 */ 78 protected Object _idValue; 79 80 /* 81 /********************************************************** 82 /* Life-cycle 83 /********************************************************** 84 */ 85 PropertyValueBuffer(JsonParser p, DeserializationContext ctxt, int paramCount, ObjectIdReader oir)86 public PropertyValueBuffer(JsonParser p, DeserializationContext ctxt, int paramCount, 87 ObjectIdReader oir) 88 { 89 _parser = p; 90 _context = ctxt; 91 _paramsNeeded = paramCount; 92 _objectIdReader = oir; 93 _creatorParameters = new Object[paramCount]; 94 if (paramCount < 32) { 95 _paramsSeenBig = null; 96 } else { 97 _paramsSeenBig = new BitSet(); 98 } 99 } 100 101 /** 102 * Returns {@code true} if the given property was seen in the JSON source by 103 * this buffer. 104 * 105 * @since 2.8 106 */ hasParameter(SettableBeanProperty prop)107 public final boolean hasParameter(SettableBeanProperty prop) 108 { 109 if (_paramsSeenBig == null) { 110 return ((_paramsSeen >> prop.getCreatorIndex()) & 1) == 1; 111 } 112 return _paramsSeenBig.get(prop.getCreatorIndex()); 113 } 114 115 /** 116 * A variation of {@link #getParameters(SettableBeanProperty[])} that 117 * accepts a single property. Whereas the plural form eagerly fetches and 118 * validates all properties, this method may be used (along with 119 * {@link #hasParameter(SettableBeanProperty)}) to let applications only 120 * fetch the properties defined in the JSON source itself, and to have some 121 * other customized behavior for missing properties. 122 * 123 * @since 2.8 124 */ getParameter(SettableBeanProperty prop)125 public Object getParameter(SettableBeanProperty prop) 126 throws JsonMappingException 127 { 128 Object value; 129 if (hasParameter(prop)) { 130 value = _creatorParameters[prop.getCreatorIndex()]; 131 } else { 132 value = _creatorParameters[prop.getCreatorIndex()] = _findMissing(prop); 133 } 134 if (value == null && _context.isEnabled(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)) { 135 return _context.reportInputMismatch(prop, 136 "Null value for creator property '%s' (index %d); `DeserializationFeature.FAIL_ON_NULL_FOR_CREATOR_PARAMETERS` enabled", 137 prop.getName(), prop.getCreatorIndex()); 138 } 139 return value; 140 } 141 142 /** 143 * Method called to do necessary post-processing such as injection of values 144 * and verification of values for required properties, 145 * after either {@link #assignParameter(SettableBeanProperty, Object)} 146 * returns <code>true</code> (to indicate all creator properties are found), or when 147 * then whole JSON Object has been processed, 148 */ getParameters(SettableBeanProperty[] props)149 public Object[] getParameters(SettableBeanProperty[] props) 150 throws JsonMappingException 151 { 152 // quick check to see if anything else is needed 153 if (_paramsNeeded > 0) { 154 if (_paramsSeenBig == null) { 155 int mask = _paramsSeen; 156 // not optimal, could use `Integer.trailingZeroes()`, but for now should not 157 // really matter for common cases 158 for (int ix = 0, len = _creatorParameters.length; ix < len; ++ix, mask >>= 1) { 159 if ((mask & 1) == 0) { 160 _creatorParameters[ix] = _findMissing(props[ix]); 161 } 162 } 163 } else { 164 final int len = _creatorParameters.length; 165 for (int ix = 0; (ix = _paramsSeenBig.nextClearBit(ix)) < len; ++ix) { 166 _creatorParameters[ix] = _findMissing(props[ix]); 167 } 168 } 169 } 170 171 if (_context.isEnabled(DeserializationFeature.FAIL_ON_NULL_CREATOR_PROPERTIES)) { 172 for (int ix = 0; ix < props.length; ++ix) { 173 if (_creatorParameters[ix] == null) { 174 SettableBeanProperty prop = props[ix]; 175 _context.reportInputMismatch(prop, 176 "Null value for creator property '%s' (index %d); `DeserializationFeature.FAIL_ON_NULL_FOR_CREATOR_PARAMETERS` enabled", 177 prop.getName(), props[ix].getCreatorIndex()); 178 } 179 } 180 } 181 return _creatorParameters; 182 } 183 _findMissing(SettableBeanProperty prop)184 protected Object _findMissing(SettableBeanProperty prop) throws JsonMappingException 185 { 186 // First: do we have injectable value? 187 Object injectableValueId = prop.getInjectableValueId(); 188 if (injectableValueId != null) { 189 return _context.findInjectableValue(prop.getInjectableValueId(), 190 prop, null); 191 } 192 // Second: required? 193 if (prop.isRequired()) { 194 _context.reportInputMismatch(prop, "Missing required creator property '%s' (index %d)", 195 prop.getName(), prop.getCreatorIndex()); 196 } 197 if (_context.isEnabled(DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES)) { 198 _context.reportInputMismatch(prop, 199 "Missing creator property '%s' (index %d); `DeserializationFeature.FAIL_ON_MISSING_CREATOR_PROPERTIES` enabled", 200 prop.getName(), prop.getCreatorIndex()); 201 } 202 try { 203 // Third: NullValueProvider? (22-Sep-2019, [databind#2458]) 204 Object nullValue = prop.getNullValueProvider().getNullValue(_context); 205 if (nullValue != null) { 206 return nullValue; 207 } 208 209 // Fourth: default value 210 JsonDeserializer<Object> deser = prop.getValueDeserializer(); 211 return deser.getNullValue(_context); 212 } catch (JsonMappingException e) { 213 // [databind#2101]: Include property name, if we have it 214 AnnotatedMember member = prop.getMember(); 215 if (member != null) { 216 e.prependPath(member.getDeclaringClass(), prop.getName()); 217 } 218 throw e; 219 } 220 } 221 222 /* 223 /********************************************************** 224 /* Other methods 225 /********************************************************** 226 */ 227 228 /** 229 * Helper method called to see if given non-creator property is the "id property"; 230 * and if so, handle appropriately. 231 * 232 * @since 2.1 233 */ readIdProperty(String propName)234 public boolean readIdProperty(String propName) throws IOException 235 { 236 if ((_objectIdReader != null) && propName.equals(_objectIdReader.propertyName.getSimpleName())) { 237 _idValue = _objectIdReader.readObjectReference(_parser, _context); 238 return true; 239 } 240 return false; 241 } 242 243 /** 244 * Helper method called to handle Object Id value collected earlier, if any 245 */ handleIdValue(final DeserializationContext ctxt, Object bean)246 public Object handleIdValue(final DeserializationContext ctxt, Object bean) throws IOException 247 { 248 if (_objectIdReader != null) { 249 if (_idValue != null) { 250 ReadableObjectId roid = ctxt.findObjectId(_idValue, _objectIdReader.generator, _objectIdReader.resolver); 251 roid.bindItem(bean); 252 // also: may need to set a property value as well 253 SettableBeanProperty idProp = _objectIdReader.idProperty; 254 if (idProp != null) { 255 return idProp.setAndReturn(bean, _idValue); 256 } 257 } else { 258 // 07-Jun-2016, tatu: Trying to improve error messaging here... 259 ctxt.reportUnresolvedObjectId(_objectIdReader, bean); 260 } 261 } 262 return bean; 263 } 264 buffered()265 protected PropertyValue buffered() { return _buffered; } 266 isComplete()267 public boolean isComplete() { return _paramsNeeded <= 0; } 268 269 /** 270 * Method called to buffer value for given property, as well as check whether 271 * we now have values for all (creator) properties that we expect to get values for. 272 * 273 * @return True if we have received all creator parameters 274 * 275 * @since 2.6 276 */ assignParameter(SettableBeanProperty prop, Object value)277 public boolean assignParameter(SettableBeanProperty prop, Object value) 278 { 279 final int ix = prop.getCreatorIndex(); 280 _creatorParameters[ix] = value; 281 if (_paramsSeenBig == null) { 282 int old = _paramsSeen; 283 int newValue = (old | (1 << ix)); 284 if (old != newValue) { 285 _paramsSeen = newValue; 286 if (--_paramsNeeded <= 0) { 287 // 29-Nov-2016, tatu: But! May still require Object Id value 288 return (_objectIdReader == null) || (_idValue != null); 289 } 290 } 291 } else { 292 if (!_paramsSeenBig.get(ix)) { 293 _paramsSeenBig.set(ix); 294 if (--_paramsNeeded <= 0) { 295 // 29-Nov-2016, tatu: But! May still require Object Id value 296 } 297 } 298 } 299 return false; 300 } 301 bufferProperty(SettableBeanProperty prop, Object value)302 public void bufferProperty(SettableBeanProperty prop, Object value) { 303 _buffered = new PropertyValue.Regular(_buffered, value, prop); 304 } 305 bufferAnyProperty(SettableAnyProperty prop, String propName, Object value)306 public void bufferAnyProperty(SettableAnyProperty prop, String propName, Object value) { 307 _buffered = new PropertyValue.Any(_buffered, value, prop, propName); 308 } 309 bufferMapProperty(Object key, Object value)310 public void bufferMapProperty(Object key, Object value) { 311 _buffered = new PropertyValue.Map(_buffered, value, key); 312 } 313 } 314