1 package com.fasterxml.jackson.databind; 2 3 import java.lang.reflect.Type; 4 import java.util.Locale; 5 import java.util.TimeZone; 6 7 import com.fasterxml.jackson.annotation.*; 8 9 import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; 10 import com.fasterxml.jackson.databind.cfg.MapperConfig; 11 import com.fasterxml.jackson.databind.introspect.Annotated; 12 import com.fasterxml.jackson.databind.introspect.ObjectIdInfo; 13 import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; 14 import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator.Validity; 15 import com.fasterxml.jackson.databind.type.TypeFactory; 16 import com.fasterxml.jackson.databind.util.ClassUtil; 17 import com.fasterxml.jackson.databind.util.Converter; 18 19 /** 20 * Shared base class for {@link DeserializationContext} and 21 * {@link SerializerProvider}, context objects passed through data-binding 22 * process. Designed so that some of implementations can rely on shared 23 * aspects like access to secondary contextual objects like type factories 24 * or handler instantiators. 25 * 26 * @since 2.2 27 */ 28 public abstract class DatabindContext 29 { 30 /** 31 * Let's limit length of error messages, for cases where underlying data 32 * may be very large -- no point in spamming logs with megabytes of meaningless 33 * data. 34 * 35 * @since 2.9 36 */ 37 private final static int MAX_ERROR_STR_LEN = 500; 38 39 /* 40 /********************************************************** 41 /* Generic config access 42 /********************************************************** 43 */ 44 45 /** 46 * Accessor to currently active configuration (both per-request configs 47 * and per-mapper config). 48 */ getConfig()49 public abstract MapperConfig<?> getConfig(); 50 51 /** 52 * Convenience method for accessing serialization view in use (if any); equivalent to: 53 *<pre> 54 * getConfig().getAnnotationIntrospector(); 55 *</pre> 56 */ getAnnotationIntrospector()57 public abstract AnnotationIntrospector getAnnotationIntrospector(); 58 59 /* 60 /********************************************************** 61 /* Access to specific config settings 62 /********************************************************** 63 */ 64 65 /** 66 * Convenience method for checking whether specified serialization 67 * feature is enabled or not. 68 * Shortcut for: 69 *<pre> 70 * getConfig().isEnabled(feature); 71 *</pre> 72 */ isEnabled(MapperFeature feature)73 public abstract boolean isEnabled(MapperFeature feature); 74 75 /** 76 * Convenience method for accessing serialization view in use (if any); equivalent to: 77 *<pre> 78 * getConfig().canOverrideAccessModifiers(); 79 *</pre> 80 */ canOverrideAccessModifiers()81 public abstract boolean canOverrideAccessModifiers(); 82 83 /** 84 * Accessor for locating currently active view, if any; 85 * returns null if no view has been set. 86 */ getActiveView()87 public abstract Class<?> getActiveView(); 88 89 /** 90 * @since 2.6 91 */ getLocale()92 public abstract Locale getLocale(); 93 94 /** 95 * @since 2.6 96 */ getTimeZone()97 public abstract TimeZone getTimeZone(); 98 99 /** 100 * @since 2.7 101 */ getDefaultPropertyFormat(Class<?> baseType)102 public abstract JsonFormat.Value getDefaultPropertyFormat(Class<?> baseType); 103 104 /* 105 /********************************************************** 106 /* Generic attributes (2.3+) 107 /********************************************************** 108 */ 109 110 /** 111 * Method for accessing attributes available in this context. 112 * Per-call attributes have highest precedence; attributes set 113 * via {@link ObjectReader} or {@link ObjectWriter} have lower 114 * precedence. 115 * 116 * @param key Key of the attribute to get 117 * @return Value of the attribute, if any; null otherwise 118 * 119 * @since 2.3 120 */ getAttribute(Object key)121 public abstract Object getAttribute(Object key); 122 123 /** 124 * Method for setting per-call value of given attribute. 125 * This will override any previously defined value for the 126 * attribute within this context. 127 * 128 * @param key Key of the attribute to set 129 * @param value Value to set attribute to 130 * 131 * @return This context object, to allow chaining 132 * 133 * @since 2.3 134 */ setAttribute(Object key, Object value)135 public abstract DatabindContext setAttribute(Object key, Object value); 136 137 /* 138 /********************************************************** 139 /* Type instantiation/resolution 140 /********************************************************** 141 */ 142 143 /** 144 * Convenience method for constructing {@link JavaType} for given JDK 145 * type (usually {@link java.lang.Class}) 146 */ constructType(Type type)147 public JavaType constructType(Type type) { 148 if (type == null) { 149 return null; 150 } 151 return getTypeFactory().constructType(type); 152 } 153 154 /** 155 * Convenience method for constructing subtypes, retaining generic 156 * type parameter (if any). 157 *<p> 158 * Note: since 2.11 handling has varied a bit across serialization, deserialization. 159 */ constructSpecializedType(JavaType baseType, Class<?> subclass)160 public abstract JavaType constructSpecializedType(JavaType baseType, Class<?> subclass); 161 162 /** 163 * Lookup method called when code needs to resolve class name from input; 164 * usually simple lookup. 165 * Note that unlike {@link #resolveAndValidateSubType} this method DOES NOT 166 * validate subtype against configured {@link PolymorphicTypeValidator}: usually 167 * because such check has already been made. 168 * 169 * @since 2.9 170 */ resolveSubType(JavaType baseType, String subClassName)171 public JavaType resolveSubType(JavaType baseType, String subClassName) 172 throws JsonMappingException 173 { 174 // 30-Jan-2010, tatu: Most ids are basic class names; so let's first 175 // check if any generics info is added; and only then ask factory 176 // to do translation when necessary 177 if (subClassName.indexOf('<') > 0) { 178 // note: may want to try combining with specialization (esp for EnumMap)? 179 // 17-Aug-2017, tatu: As per [databind#1735] need to ensure assignment 180 // compatibility -- needed later anyway, and not doing so may open 181 // security issues. 182 JavaType t = getTypeFactory().constructFromCanonical(subClassName); 183 if (t.isTypeOrSubTypeOf(baseType.getRawClass())) { 184 return t; 185 } 186 } else { 187 Class<?> cls; 188 try { 189 cls = getTypeFactory().findClass(subClassName); 190 } catch (ClassNotFoundException e) { // let caller handle this problem 191 return null; 192 } catch (Exception e) { 193 throw invalidTypeIdException(baseType, subClassName, String.format( 194 "problem: (%s) %s", 195 e.getClass().getName(), 196 ClassUtil.exceptionMessage(e))); 197 } 198 if (baseType.isTypeOrSuperTypeOf(cls)) { 199 return getTypeFactory().constructSpecializedType(baseType, cls); 200 } 201 } 202 throw invalidTypeIdException(baseType, subClassName, "Not a subtype"); 203 } 204 205 /** 206 * Lookup method similar to {@link #resolveSubType} but one that also validates 207 * that resulting subtype is valid according to given {@link PolymorphicTypeValidator}. 208 * 209 * @since 2.10 210 */ resolveAndValidateSubType(JavaType baseType, String subClass, PolymorphicTypeValidator ptv)211 public JavaType resolveAndValidateSubType(JavaType baseType, String subClass, 212 PolymorphicTypeValidator ptv) 213 throws JsonMappingException 214 { 215 // Off-line the special case of generic (parameterized) type: 216 final int ltIndex = subClass.indexOf('<'); 217 if (ltIndex > 0) { 218 return _resolveAndValidateGeneric(baseType, subClass, ptv, ltIndex); 219 } 220 final MapperConfig<?> config = getConfig(); 221 PolymorphicTypeValidator.Validity vld = ptv.validateSubClassName(config, baseType, subClass); 222 if (vld == Validity.DENIED) { 223 return _throwSubtypeNameNotAllowed(baseType, subClass, ptv); 224 } 225 final Class<?> cls; 226 try { 227 cls = getTypeFactory().findClass(subClass); 228 } catch (ClassNotFoundException e) { // let caller handle this problem 229 return null; 230 } catch (Exception e) { 231 throw invalidTypeIdException(baseType, subClass, String.format( 232 "problem: (%s) %s", 233 e.getClass().getName(), 234 ClassUtil.exceptionMessage(e))); 235 } 236 if (!baseType.isTypeOrSuperTypeOf(cls)) { 237 return _throwNotASubtype(baseType, subClass); 238 } 239 final JavaType subType = config.getTypeFactory().constructSpecializedType(baseType, cls); 240 // May skip check if type was allowed by subclass name already 241 if (vld == Validity.INDETERMINATE) { 242 vld = ptv.validateSubType(config, baseType, subType); 243 if (vld != Validity.ALLOWED) { 244 return _throwSubtypeClassNotAllowed(baseType, subClass, ptv); 245 } 246 } 247 return subType; 248 } 249 _resolveAndValidateGeneric(JavaType baseType, String subClass, PolymorphicTypeValidator ptv, int ltIndex)250 private JavaType _resolveAndValidateGeneric(JavaType baseType, String subClass, 251 PolymorphicTypeValidator ptv, int ltIndex) 252 throws JsonMappingException 253 { 254 final MapperConfig<?> config = getConfig(); 255 // 24-Apr-2019, tatu: Not 100% sure if we should pass name with type parameters 256 // or not, but guessing it's more convenient not to have to worry about it so 257 // strip out 258 PolymorphicTypeValidator.Validity vld = ptv.validateSubClassName(config, baseType, subClass.substring(0, ltIndex)); 259 if (vld == Validity.DENIED) { 260 return _throwSubtypeNameNotAllowed(baseType, subClass, ptv); 261 } 262 JavaType subType = getTypeFactory().constructFromCanonical(subClass); 263 if (!subType.isTypeOrSubTypeOf(baseType.getRawClass())) { 264 return _throwNotASubtype(baseType, subClass); 265 } 266 // Unless we were approved already by name, check that actual sub-class acceptable: 267 if (vld != Validity.ALLOWED) { 268 if (ptv.validateSubType(config, baseType, subType) != Validity.ALLOWED) { 269 return _throwSubtypeClassNotAllowed(baseType, subClass, ptv); 270 } 271 } 272 return subType; 273 } 274 _throwNotASubtype(JavaType baseType, String subType)275 protected <T> T _throwNotASubtype(JavaType baseType, String subType) throws JsonMappingException { 276 throw invalidTypeIdException(baseType, subType, "Not a subtype"); 277 } 278 _throwSubtypeNameNotAllowed(JavaType baseType, String subType, PolymorphicTypeValidator ptv)279 protected <T> T _throwSubtypeNameNotAllowed(JavaType baseType, String subType, 280 PolymorphicTypeValidator ptv) throws JsonMappingException { 281 throw invalidTypeIdException(baseType, subType, 282 "Configured `PolymorphicTypeValidator` (of type "+ClassUtil.classNameOf(ptv)+") denied resolution"); 283 } 284 _throwSubtypeClassNotAllowed(JavaType baseType, String subType, PolymorphicTypeValidator ptv)285 protected <T> T _throwSubtypeClassNotAllowed(JavaType baseType, String subType, 286 PolymorphicTypeValidator ptv) throws JsonMappingException { 287 throw invalidTypeIdException(baseType, subType, 288 "Configured `PolymorphicTypeValidator` (of type "+ClassUtil.classNameOf(ptv)+") denied resolution"); 289 } 290 291 /** 292 * Helper method for constructing exception to indicate that given type id 293 * could not be resolved to a valid subtype of specified base type. 294 * Most commonly called during polymorphic deserialization. 295 *<p> 296 * Note that most of the time this method should NOT be called directly: instead, 297 * method <code>handleUnknownTypeId()</code> should be called which will call this method 298 * if necessary. 299 * 300 * @since 2.9 301 */ invalidTypeIdException(JavaType baseType, String typeId, String extraDesc)302 protected abstract JsonMappingException invalidTypeIdException(JavaType baseType, String typeId, 303 String extraDesc); 304 getTypeFactory()305 public abstract TypeFactory getTypeFactory(); 306 307 /* 308 /********************************************************** 309 /* Helper object construction 310 /********************************************************** 311 */ 312 objectIdGeneratorInstance(Annotated annotated, ObjectIdInfo objectIdInfo)313 public ObjectIdGenerator<?> objectIdGeneratorInstance(Annotated annotated, 314 ObjectIdInfo objectIdInfo) 315 throws JsonMappingException 316 { 317 Class<?> implClass = objectIdInfo.getGeneratorType(); 318 final MapperConfig<?> config = getConfig(); 319 HandlerInstantiator hi = config.getHandlerInstantiator(); 320 ObjectIdGenerator<?> gen = (hi == null) ? null : hi.objectIdGeneratorInstance(config, annotated, implClass); 321 if (gen == null) { 322 gen = (ObjectIdGenerator<?>) ClassUtil.createInstance(implClass, 323 config.canOverrideAccessModifiers()); 324 } 325 return gen.forScope(objectIdInfo.getScope()); 326 } 327 objectIdResolverInstance(Annotated annotated, ObjectIdInfo objectIdInfo)328 public ObjectIdResolver objectIdResolverInstance(Annotated annotated, ObjectIdInfo objectIdInfo) 329 { 330 Class<? extends ObjectIdResolver> implClass = objectIdInfo.getResolverType(); 331 final MapperConfig<?> config = getConfig(); 332 HandlerInstantiator hi = config.getHandlerInstantiator(); 333 ObjectIdResolver resolver = (hi == null) ? null : hi.resolverIdGeneratorInstance(config, annotated, implClass); 334 if (resolver == null) { 335 resolver = ClassUtil.createInstance(implClass, config.canOverrideAccessModifiers()); 336 } 337 338 return resolver; 339 } 340 341 /** 342 * Helper method to use to construct a {@link Converter}, given a definition 343 * that may be either actual converter instance, or Class for instantiating one. 344 * 345 * @since 2.2 346 */ 347 @SuppressWarnings("unchecked") converterInstance(Annotated annotated, Object converterDef)348 public Converter<Object,Object> converterInstance(Annotated annotated, 349 Object converterDef) 350 throws JsonMappingException 351 { 352 if (converterDef == null) { 353 return null; 354 } 355 if (converterDef instanceof Converter<?,?>) { 356 return (Converter<Object,Object>) converterDef; 357 } 358 if (!(converterDef instanceof Class)) { 359 throw new IllegalStateException("AnnotationIntrospector returned Converter definition of type " 360 +converterDef.getClass().getName()+"; expected type Converter or Class<Converter> instead"); 361 } 362 Class<?> converterClass = (Class<?>)converterDef; 363 // there are some known "no class" markers to consider too: 364 if (converterClass == Converter.None.class || ClassUtil.isBogusClass(converterClass)) { 365 return null; 366 } 367 if (!Converter.class.isAssignableFrom(converterClass)) { 368 throw new IllegalStateException("AnnotationIntrospector returned Class " 369 +converterClass.getName()+"; expected Class<Converter>"); 370 } 371 final MapperConfig<?> config = getConfig(); 372 HandlerInstantiator hi = config.getHandlerInstantiator(); 373 Converter<?,?> conv = (hi == null) ? null : hi.converterInstance(config, annotated, converterClass); 374 if (conv == null) { 375 conv = (Converter<?,?>) ClassUtil.createInstance(converterClass, 376 config.canOverrideAccessModifiers()); 377 } 378 return (Converter<Object,Object>) conv; 379 } 380 381 /* 382 /********************************************************** 383 /* Error reporting 384 /********************************************************** 385 */ 386 387 /** 388 * Helper method called to indicate a generic problem that stems from type 389 * definition(s), not input data, or input/output state; typically this 390 * means throwing a {@link com.fasterxml.jackson.databind.exc.InvalidDefinitionException}. 391 * 392 * @since 2.9 393 */ reportBadDefinition(JavaType type, String msg)394 public abstract <T> T reportBadDefinition(JavaType type, String msg) throws JsonMappingException; 395 396 /** 397 * @since 2.9 398 */ reportBadDefinition(Class<?> type, String msg)399 public <T> T reportBadDefinition(Class<?> type, String msg) throws JsonMappingException { 400 return reportBadDefinition(constructType(type), msg); 401 } 402 403 /* 404 /********************************************************** 405 /* Helper methods 406 /********************************************************** 407 */ 408 409 /** 410 * @since 2.9 411 */ _format(String msg, Object... msgArgs)412 protected final String _format(String msg, Object... msgArgs) { 413 if (msgArgs.length > 0) { 414 return String.format(msg, msgArgs); 415 } 416 return msg; 417 } 418 419 /** 420 * @since 2.9 421 */ _truncate(String desc)422 protected final String _truncate(String desc) { 423 if (desc == null) { 424 return ""; 425 } 426 if (desc.length() <= MAX_ERROR_STR_LEN) { 427 return desc; 428 } 429 return desc.substring(0, MAX_ERROR_STR_LEN) + "]...[" + desc.substring(desc.length() - MAX_ERROR_STR_LEN); 430 } 431 432 /** 433 * @since 2.9 434 */ _quotedString(String desc)435 protected String _quotedString(String desc) { 436 if (desc == null) { 437 return "[N/A]"; 438 } 439 // !!! should we quote it? (in case there are control chars, linefeeds) 440 return String.format("\"%s\"", _truncate(desc)); 441 } 442 443 /** 444 * @since 2.9 445 */ _colonConcat(String msgBase, String extra)446 protected String _colonConcat(String msgBase, String extra) { 447 if (extra == null) { 448 return msgBase; 449 } 450 return msgBase + ": " + extra; 451 } 452 453 /** 454 * @since 2.9 455 */ _desc(String desc)456 protected String _desc(String desc) { 457 if (desc == null) { 458 return "[N/A]"; 459 } 460 // !!! should we quote it? (in case there are control chars, linefeeds) 461 return _truncate(desc); 462 } 463 } 464