package com.fasterxml.jackson.databind; import java.lang.reflect.Type; import java.util.Locale; import java.util.TimeZone; import com.fasterxml.jackson.annotation.*; import com.fasterxml.jackson.databind.cfg.HandlerInstantiator; import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.introspect.Annotated; import com.fasterxml.jackson.databind.introspect.ObjectIdInfo; import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator; import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator.Validity; import com.fasterxml.jackson.databind.type.TypeFactory; import com.fasterxml.jackson.databind.util.ClassUtil; import com.fasterxml.jackson.databind.util.Converter; /** * Shared base class for {@link DeserializationContext} and * {@link SerializerProvider}, context objects passed through data-binding * process. Designed so that some of implementations can rely on shared * aspects like access to secondary contextual objects like type factories * or handler instantiators. * * @since 2.2 */ public abstract class DatabindContext { /** * Let's limit length of error messages, for cases where underlying data * may be very large -- no point in spamming logs with megabytes of meaningless * data. * * @since 2.9 */ private final static int MAX_ERROR_STR_LEN = 500; /* /********************************************************** /* Generic config access /********************************************************** */ /** * Accessor to currently active configuration (both per-request configs * and per-mapper config). */ public abstract MapperConfig> getConfig(); /** * Convenience method for accessing serialization view in use (if any); equivalent to: *
* getConfig().getAnnotationIntrospector(); **/ public abstract AnnotationIntrospector getAnnotationIntrospector(); /* /********************************************************** /* Access to specific config settings /********************************************************** */ /** * Convenience method for checking whether specified serialization * feature is enabled or not. * Shortcut for: *
* getConfig().isEnabled(feature); **/ public abstract boolean isEnabled(MapperFeature feature); /** * Convenience method for accessing serialization view in use (if any); equivalent to: *
* getConfig().canOverrideAccessModifiers(); **/ public abstract boolean canOverrideAccessModifiers(); /** * Accessor for locating currently active view, if any; * returns null if no view has been set. */ public abstract Class> getActiveView(); /** * @since 2.6 */ public abstract Locale getLocale(); /** * @since 2.6 */ public abstract TimeZone getTimeZone(); /** * @since 2.7 */ public abstract JsonFormat.Value getDefaultPropertyFormat(Class> baseType); /* /********************************************************** /* Generic attributes (2.3+) /********************************************************** */ /** * Method for accessing attributes available in this context. * Per-call attributes have highest precedence; attributes set * via {@link ObjectReader} or {@link ObjectWriter} have lower * precedence. * * @param key Key of the attribute to get * @return Value of the attribute, if any; null otherwise * * @since 2.3 */ public abstract Object getAttribute(Object key); /** * Method for setting per-call value of given attribute. * This will override any previously defined value for the * attribute within this context. * * @param key Key of the attribute to set * @param value Value to set attribute to * * @return This context object, to allow chaining * * @since 2.3 */ public abstract DatabindContext setAttribute(Object key, Object value); /* /********************************************************** /* Type instantiation/resolution /********************************************************** */ /** * Convenience method for constructing {@link JavaType} for given JDK * type (usually {@link java.lang.Class}) */ public JavaType constructType(Type type) { if (type == null) { return null; } return getTypeFactory().constructType(type); } /** * Convenience method for constructing subtypes, retaining generic * type parameter (if any). *
* Note: since 2.11 handling has varied a bit across serialization, deserialization.
*/
public abstract JavaType constructSpecializedType(JavaType baseType, Class> subclass);
/**
* Lookup method called when code needs to resolve class name from input;
* usually simple lookup.
* Note that unlike {@link #resolveAndValidateSubType} this method DOES NOT
* validate subtype against configured {@link PolymorphicTypeValidator}: usually
* because such check has already been made.
*
* @since 2.9
*/
public JavaType resolveSubType(JavaType baseType, String subClassName)
throws JsonMappingException
{
// 30-Jan-2010, tatu: Most ids are basic class names; so let's first
// check if any generics info is added; and only then ask factory
// to do translation when necessary
if (subClassName.indexOf('<') > 0) {
// note: may want to try combining with specialization (esp for EnumMap)?
// 17-Aug-2017, tatu: As per [databind#1735] need to ensure assignment
// compatibility -- needed later anyway, and not doing so may open
// security issues.
JavaType t = getTypeFactory().constructFromCanonical(subClassName);
if (t.isTypeOrSubTypeOf(baseType.getRawClass())) {
return t;
}
} else {
Class> cls;
try {
cls = getTypeFactory().findClass(subClassName);
} catch (ClassNotFoundException e) { // let caller handle this problem
return null;
} catch (Exception e) {
throw invalidTypeIdException(baseType, subClassName, String.format(
"problem: (%s) %s",
e.getClass().getName(),
ClassUtil.exceptionMessage(e)));
}
if (baseType.isTypeOrSuperTypeOf(cls)) {
return getTypeFactory().constructSpecializedType(baseType, cls);
}
}
throw invalidTypeIdException(baseType, subClassName, "Not a subtype");
}
/**
* Lookup method similar to {@link #resolveSubType} but one that also validates
* that resulting subtype is valid according to given {@link PolymorphicTypeValidator}.
*
* @since 2.10
*/
public JavaType resolveAndValidateSubType(JavaType baseType, String subClass,
PolymorphicTypeValidator ptv)
throws JsonMappingException
{
// Off-line the special case of generic (parameterized) type:
final int ltIndex = subClass.indexOf('<');
if (ltIndex > 0) {
return _resolveAndValidateGeneric(baseType, subClass, ptv, ltIndex);
}
final MapperConfig> config = getConfig();
PolymorphicTypeValidator.Validity vld = ptv.validateSubClassName(config, baseType, subClass);
if (vld == Validity.DENIED) {
return _throwSubtypeNameNotAllowed(baseType, subClass, ptv);
}
final Class> cls;
try {
cls = getTypeFactory().findClass(subClass);
} catch (ClassNotFoundException e) { // let caller handle this problem
return null;
} catch (Exception e) {
throw invalidTypeIdException(baseType, subClass, String.format(
"problem: (%s) %s",
e.getClass().getName(),
ClassUtil.exceptionMessage(e)));
}
if (!baseType.isTypeOrSuperTypeOf(cls)) {
return _throwNotASubtype(baseType, subClass);
}
final JavaType subType = config.getTypeFactory().constructSpecializedType(baseType, cls);
// May skip check if type was allowed by subclass name already
if (vld == Validity.INDETERMINATE) {
vld = ptv.validateSubType(config, baseType, subType);
if (vld != Validity.ALLOWED) {
return _throwSubtypeClassNotAllowed(baseType, subClass, ptv);
}
}
return subType;
}
private JavaType _resolveAndValidateGeneric(JavaType baseType, String subClass,
PolymorphicTypeValidator ptv, int ltIndex)
throws JsonMappingException
{
final MapperConfig> config = getConfig();
// 24-Apr-2019, tatu: Not 100% sure if we should pass name with type parameters
// or not, but guessing it's more convenient not to have to worry about it so
// strip out
PolymorphicTypeValidator.Validity vld = ptv.validateSubClassName(config, baseType, subClass.substring(0, ltIndex));
if (vld == Validity.DENIED) {
return _throwSubtypeNameNotAllowed(baseType, subClass, ptv);
}
JavaType subType = getTypeFactory().constructFromCanonical(subClass);
if (!subType.isTypeOrSubTypeOf(baseType.getRawClass())) {
return _throwNotASubtype(baseType, subClass);
}
// Unless we were approved already by name, check that actual sub-class acceptable:
if (vld != Validity.ALLOWED) {
if (ptv.validateSubType(config, baseType, subType) != Validity.ALLOWED) {
return _throwSubtypeClassNotAllowed(baseType, subClass, ptv);
}
}
return subType;
}
protected
* Note that most of the time this method should NOT be called directly: instead,
* method handleUnknownTypeId()
should be called which will call this method
* if necessary.
*
* @since 2.9
*/
protected abstract JsonMappingException invalidTypeIdException(JavaType baseType, String typeId,
String extraDesc);
public abstract TypeFactory getTypeFactory();
/*
/**********************************************************
/* Helper object construction
/**********************************************************
*/
public ObjectIdGenerator> objectIdGeneratorInstance(Annotated annotated,
ObjectIdInfo objectIdInfo)
throws JsonMappingException
{
Class> implClass = objectIdInfo.getGeneratorType();
final MapperConfig> config = getConfig();
HandlerInstantiator hi = config.getHandlerInstantiator();
ObjectIdGenerator> gen = (hi == null) ? null : hi.objectIdGeneratorInstance(config, annotated, implClass);
if (gen == null) {
gen = (ObjectIdGenerator>) ClassUtil.createInstance(implClass,
config.canOverrideAccessModifiers());
}
return gen.forScope(objectIdInfo.getScope());
}
public ObjectIdResolver objectIdResolverInstance(Annotated annotated, ObjectIdInfo objectIdInfo)
{
Class extends ObjectIdResolver> implClass = objectIdInfo.getResolverType();
final MapperConfig> config = getConfig();
HandlerInstantiator hi = config.getHandlerInstantiator();
ObjectIdResolver resolver = (hi == null) ? null : hi.resolverIdGeneratorInstance(config, annotated, implClass);
if (resolver == null) {
resolver = ClassUtil.createInstance(implClass, config.canOverrideAccessModifiers());
}
return resolver;
}
/**
* Helper method to use to construct a {@link Converter}, given a definition
* that may be either actual converter instance, or Class for instantiating one.
*
* @since 2.2
*/
@SuppressWarnings("unchecked")
public Converter