• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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