1 package com.fasterxml.jackson.databind.deser.impl; 2 3 import java.lang.reflect.Member; 4 import java.util.*; 5 6 import com.fasterxml.jackson.databind.*; 7 import com.fasterxml.jackson.databind.cfg.MapperConfig; 8 import com.fasterxml.jackson.databind.deser.SettableBeanProperty; 9 import com.fasterxml.jackson.databind.deser.ValueInstantiator; 10 import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator; 11 import com.fasterxml.jackson.databind.introspect.*; 12 import com.fasterxml.jackson.databind.util.ClassUtil; 13 14 /** 15 * Container class for storing information on creators (based on annotations, 16 * visibility), to be able to build actual instantiator later on. 17 */ 18 public class CreatorCollector { 19 // Since 2.5 20 protected final static int C_DEFAULT = 0; 21 protected final static int C_STRING = 1; 22 protected final static int C_INT = 2; 23 protected final static int C_LONG = 3; 24 protected final static int C_BIG_INTEGER = 4; 25 protected final static int C_DOUBLE = 5; 26 protected final static int C_BIG_DECIMAL = 6; 27 protected final static int C_BOOLEAN = 7; 28 protected final static int C_DELEGATE = 8; 29 protected final static int C_PROPS = 9; 30 protected final static int C_ARRAY_DELEGATE = 10; 31 32 protected final static String[] TYPE_DESCS = new String[] { "default", 33 "from-String", "from-int", "from-long", "from-big-integer", "from-double", 34 "from-big-decimal", "from-boolean", "delegate", "property-based", "array-delegate" 35 }; 36 37 // Type of bean being created 38 final protected BeanDescription _beanDesc; 39 40 final protected boolean _canFixAccess; 41 42 /** 43 * @since 2.7 44 */ 45 final protected boolean _forceAccess; 46 47 /** 48 * Set of creators we have collected so far 49 * 50 * @since 2.5 51 */ 52 final protected AnnotatedWithParams[] _creators = new AnnotatedWithParams[11]; 53 54 /** 55 * Bitmask of creators that were explicitly marked as creators; false for 56 * auto-detected (ones included base on naming and/or visibility, not 57 * annotation) 58 * 59 * @since 2.5 60 */ 61 protected int _explicitCreators = 0; 62 63 protected boolean _hasNonDefaultCreator = false; 64 65 // when there are injectable values along with delegate: 66 protected SettableBeanProperty[] _delegateArgs; 67 68 protected SettableBeanProperty[] _arrayDelegateArgs; 69 70 protected SettableBeanProperty[] _propertyBasedArgs; 71 72 /* 73 /********************************************************** 74 /* Life-cycle 75 /********************************************************** 76 */ 77 CreatorCollector(BeanDescription beanDesc, MapperConfig<?> config)78 public CreatorCollector(BeanDescription beanDesc, MapperConfig<?> config) { 79 _beanDesc = beanDesc; 80 _canFixAccess = config.canOverrideAccessModifiers(); 81 _forceAccess = config 82 .isEnabled(MapperFeature.OVERRIDE_PUBLIC_ACCESS_MODIFIERS); 83 } 84 constructValueInstantiator(DeserializationContext ctxt)85 public ValueInstantiator constructValueInstantiator(DeserializationContext ctxt) 86 throws JsonMappingException 87 { 88 final DeserializationConfig config = ctxt.getConfig(); 89 final JavaType delegateType = _computeDelegateType(ctxt, 90 _creators[C_DELEGATE], _delegateArgs); 91 final JavaType arrayDelegateType = _computeDelegateType(ctxt, 92 _creators[C_ARRAY_DELEGATE], _arrayDelegateArgs); 93 final JavaType type = _beanDesc.getType(); 94 95 StdValueInstantiator inst = new StdValueInstantiator(config, type); 96 inst.configureFromObjectSettings(_creators[C_DEFAULT], _creators[C_DELEGATE], 97 delegateType, _delegateArgs, _creators[C_PROPS], 98 _propertyBasedArgs); 99 inst.configureFromArraySettings(_creators[C_ARRAY_DELEGATE], 100 arrayDelegateType, _arrayDelegateArgs); 101 inst.configureFromStringCreator(_creators[C_STRING]); 102 inst.configureFromIntCreator(_creators[C_INT]); 103 inst.configureFromLongCreator(_creators[C_LONG]); 104 inst.configureFromBigIntegerCreator(_creators[C_BIG_INTEGER]); 105 inst.configureFromDoubleCreator(_creators[C_DOUBLE]); 106 inst.configureFromBigDecimalCreator(_creators[C_BIG_DECIMAL]); 107 inst.configureFromBooleanCreator(_creators[C_BOOLEAN]); 108 return inst; 109 } 110 111 /* 112 /********************************************************** 113 /* Setters 114 /********************************************************** 115 */ 116 117 /** 118 * Method called to indicate the default creator: no-arguments constructor 119 * or factory method that is called to instantiate a value before populating 120 * it with data. Default creator is only used if no other creators are 121 * indicated. 122 * 123 * @param creator 124 * Creator method; no-arguments constructor or static factory 125 * method. 126 */ setDefaultCreator(AnnotatedWithParams creator)127 public void setDefaultCreator(AnnotatedWithParams creator) { 128 _creators[C_DEFAULT] = _fixAccess(creator); 129 } 130 addStringCreator(AnnotatedWithParams creator, boolean explicit)131 public void addStringCreator(AnnotatedWithParams creator, boolean explicit) { 132 verifyNonDup(creator, C_STRING, explicit); 133 } 134 addIntCreator(AnnotatedWithParams creator, boolean explicit)135 public void addIntCreator(AnnotatedWithParams creator, boolean explicit) { 136 verifyNonDup(creator, C_INT, explicit); 137 } 138 addLongCreator(AnnotatedWithParams creator, boolean explicit)139 public void addLongCreator(AnnotatedWithParams creator, boolean explicit) { 140 verifyNonDup(creator, C_LONG, explicit); 141 } 142 addBigIntegerCreator(AnnotatedWithParams creator, boolean explicit)143 public void addBigIntegerCreator(AnnotatedWithParams creator, boolean explicit) { 144 verifyNonDup(creator, C_BIG_INTEGER, explicit); 145 } 146 addDoubleCreator(AnnotatedWithParams creator, boolean explicit)147 public void addDoubleCreator(AnnotatedWithParams creator, boolean explicit) { 148 verifyNonDup(creator, C_DOUBLE, explicit); 149 } 150 addBigDecimalCreator(AnnotatedWithParams creator, boolean explicit)151 public void addBigDecimalCreator(AnnotatedWithParams creator, boolean explicit) { 152 verifyNonDup(creator, C_BIG_DECIMAL, explicit); 153 } 154 addBooleanCreator(AnnotatedWithParams creator, boolean explicit)155 public void addBooleanCreator(AnnotatedWithParams creator, boolean explicit) { 156 verifyNonDup(creator, C_BOOLEAN, explicit); 157 } 158 addDelegatingCreator(AnnotatedWithParams creator, boolean explicit, SettableBeanProperty[] injectables, int delegateeIndex)159 public void addDelegatingCreator(AnnotatedWithParams creator, 160 boolean explicit, SettableBeanProperty[] injectables, 161 int delegateeIndex) 162 { 163 if (creator.getParameterType(delegateeIndex).isCollectionLikeType()) { 164 if (verifyNonDup(creator, C_ARRAY_DELEGATE, explicit)) { 165 _arrayDelegateArgs = injectables; 166 } 167 } else { 168 if (verifyNonDup(creator, C_DELEGATE, explicit)) { 169 _delegateArgs = injectables; 170 } 171 } 172 } 173 addPropertyCreator(AnnotatedWithParams creator, boolean explicit, SettableBeanProperty[] properties)174 public void addPropertyCreator(AnnotatedWithParams creator, 175 boolean explicit, SettableBeanProperty[] properties) 176 { 177 if (verifyNonDup(creator, C_PROPS, explicit)) { 178 // Better ensure we have no duplicate names either... 179 if (properties.length > 1) { 180 HashMap<String, Integer> names = new HashMap<String, Integer>(); 181 for (int i = 0, len = properties.length; i < len; ++i) { 182 String name = properties[i].getName(); 183 // Need to consider Injectables, which may not have 184 // a name at all, and need to be skipped 185 if (name.isEmpty() && (properties[i].getInjectableValueId() != null)) { 186 continue; 187 } 188 Integer old = names.put(name, Integer.valueOf(i)); 189 if (old != null) { 190 throw new IllegalArgumentException(String.format( 191 "Duplicate creator property \"%s\" (index %s vs %d) for type %s ", 192 name, old, i, ClassUtil.nameOf(_beanDesc.getBeanClass()))); 193 } 194 } 195 } 196 _propertyBasedArgs = properties; 197 } 198 } 199 200 /* 201 /********************************************************** 202 /* Accessors 203 /********************************************************** 204 */ 205 206 /** 207 * @since 2.1 208 */ hasDefaultCreator()209 public boolean hasDefaultCreator() { 210 return _creators[C_DEFAULT] != null; 211 } 212 213 /** 214 * @since 2.6 215 */ hasDelegatingCreator()216 public boolean hasDelegatingCreator() { 217 return _creators[C_DELEGATE] != null; 218 } 219 220 /** 221 * @since 2.6 222 */ hasPropertyBasedCreator()223 public boolean hasPropertyBasedCreator() { 224 return _creators[C_PROPS] != null; 225 } 226 227 /* 228 /********************************************************** 229 /* Helper methods 230 /********************************************************** 231 */ 232 _computeDelegateType(DeserializationContext ctxt, AnnotatedWithParams creator, SettableBeanProperty[] delegateArgs)233 private JavaType _computeDelegateType(DeserializationContext ctxt, 234 AnnotatedWithParams creator, SettableBeanProperty[] delegateArgs) 235 throws JsonMappingException 236 { 237 if (!_hasNonDefaultCreator || (creator == null)) { 238 return null; 239 } 240 // need to find type... 241 int ix = 0; 242 if (delegateArgs != null) { 243 for (int i = 0, len = delegateArgs.length; i < len; ++i) { 244 if (delegateArgs[i] == null) { // marker for delegate itself 245 ix = i; 246 break; 247 } 248 } 249 } 250 final DeserializationConfig config = ctxt.getConfig(); 251 252 // 03-May-2018, tatu: need to check possible annotation-based 253 // custom deserializer [databind#2012], 254 // type refinement(s) [databind#2016]. 255 JavaType baseType = creator.getParameterType(ix); 256 AnnotationIntrospector intr = config.getAnnotationIntrospector(); 257 if (intr != null) { 258 AnnotatedParameter delegate = creator.getParameter(ix); 259 260 // First: custom deserializer(s): 261 Object deserDef = intr.findDeserializer(delegate); 262 if (deserDef != null) { 263 JsonDeserializer<Object> deser = ctxt.deserializerInstance(delegate, deserDef); 264 baseType = baseType.withValueHandler(deser); 265 } else { 266 // Second: type refinement(s), if no explicit deserializer was located 267 baseType = intr.refineDeserializationType(config, 268 delegate, baseType); 269 } 270 } 271 return baseType; 272 } 273 _fixAccess(T member)274 private <T extends AnnotatedMember> T _fixAccess(T member) { 275 if (member != null && _canFixAccess) { 276 ClassUtil.checkAndFixAccess((Member) member.getAnnotated(), 277 _forceAccess); 278 } 279 return member; 280 } 281 282 /** 283 * @return True if specified Creator is to be used 284 */ verifyNonDup(AnnotatedWithParams newOne, int typeIndex, boolean explicit)285 protected boolean verifyNonDup(AnnotatedWithParams newOne, int typeIndex, boolean explicit) 286 { 287 final int mask = (1 << typeIndex); 288 _hasNonDefaultCreator = true; 289 AnnotatedWithParams oldOne = _creators[typeIndex]; 290 // already had an explicitly marked one? 291 if (oldOne != null) { 292 boolean verify; 293 if ((_explicitCreators & mask) != 0) { // already had explicitly annotated, leave as-is 294 // but skip, if new one not annotated 295 if (!explicit) { 296 return false; 297 } 298 // both explicit: verify 299 verify = true; 300 } else { 301 // otherwise only verify if neither explicitly annotated. 302 verify = !explicit; 303 } 304 305 // one more thing: ok to override in sub-class 306 if (verify && (oldOne.getClass() == newOne.getClass())) { 307 // [databind#667]: avoid one particular class of bogus problems 308 Class<?> oldType = oldOne.getRawParameterType(0); 309 Class<?> newType = newOne.getRawParameterType(0); 310 311 if (oldType == newType) { 312 // 13-Jul-2016, tatu: One more thing to check; since Enum classes 313 // always have implicitly created `valueOf()`, let's resolve in 314 // favor of other implicit creator (`fromString()`) 315 if (_isEnumValueOf(newOne)) { 316 return false; // ignore 317 } 318 if (_isEnumValueOf(oldOne)) { 319 ; 320 } else { 321 _reportDuplicateCreator(typeIndex, explicit, oldOne, newOne); 322 } 323 } 324 // otherwise, which one to choose? 325 else if (newType.isAssignableFrom(oldType)) { 326 // new type more generic, use old 327 return false; 328 } else if (oldType.isAssignableFrom(newType)) { 329 // new type more specific, use it 330 ; 331 } else { 332 // 02-May-2020, tatu: Should this only result in exception if both 333 // explicit? Doing so could lead to arbitrary choice between 334 // multiple implicit creators tho? 335 _reportDuplicateCreator(typeIndex, explicit, oldOne, newOne); 336 } 337 } 338 } 339 if (explicit) { 340 _explicitCreators |= mask; 341 } 342 _creators[typeIndex] = _fixAccess(newOne); 343 return true; 344 } 345 346 // @since 2.12 _reportDuplicateCreator(int typeIndex, boolean explicit, AnnotatedWithParams oldOne, AnnotatedWithParams newOne)347 protected void _reportDuplicateCreator(int typeIndex, boolean explicit, 348 AnnotatedWithParams oldOne, AnnotatedWithParams newOne) { 349 throw new IllegalArgumentException(String.format( 350 "Conflicting %s creators: already had %s creator %s, encountered another: %s", 351 TYPE_DESCS[typeIndex], 352 explicit ? "explicitly marked" 353 : "implicitly discovered", 354 oldOne, newOne)); 355 } 356 357 /** 358 * Helper method for recognizing `Enum.valueOf()` factory method 359 * 360 * @since 2.8.1 361 */ _isEnumValueOf(AnnotatedWithParams creator)362 protected boolean _isEnumValueOf(AnnotatedWithParams creator) { 363 return ClassUtil.isEnumType(creator.getDeclaringClass()) 364 && "valueOf".equals(creator.getName()); 365 } 366 } 367