DefaultTypeResolverBuilder.java
package tools.jackson.databind.jsontype.impl;
import java.util.Collection;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import tools.jackson.core.TreeNode;
import tools.jackson.databind.*;
import tools.jackson.databind.jsontype.NamedType;
import tools.jackson.databind.jsontype.PolymorphicTypeValidator;
import tools.jackson.databind.jsontype.TypeDeserializer;
import tools.jackson.databind.jsontype.TypeResolverBuilder;
import tools.jackson.databind.jsontype.TypeSerializer;
import tools.jackson.databind.util.ClassUtil;
/**
* Customized {@link TypeResolverBuilder} that provides type resolver builders
* used with so-called "default typing"
* (see {@link tools.jackson.databind.cfg.MapperBuilder#activateDefaultTyping(PolymorphicTypeValidator)}
* for details).
*<p>
* Type resolver construction is based on configuration: implementation takes care
* of only providing builders in cases where type information should be applied.
* This is important since build calls may be sent for any and all types, and
* type information should NOT be applied to all of them.
*/
public class DefaultTypeResolverBuilder
extends StdTypeResolverBuilder
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
/**
* Validator to use for checking that only valid subtypes are accepted
* from incoming content.
*/
protected final PolymorphicTypeValidator _subtypeValidator;
/**
* Definition of what types is this default typer valid for.
*/
protected final DefaultTyping _appliesFor;
public DefaultTypeResolverBuilder(PolymorphicTypeValidator subtypeValidator,
DefaultTyping t, JsonTypeInfo.As includeAs) {
_subtypeValidator = subtypeValidator;
_appliesFor = t;
_idType = JsonTypeInfo.Id.CLASS;
_includeAs = includeAs;
_typeProperty = _idType.getDefaultPropertyName();
}
public DefaultTypeResolverBuilder(PolymorphicTypeValidator subtypeValidator,
DefaultTyping t, String propertyName) {
_subtypeValidator = subtypeValidator;
_appliesFor = t;
_idType = JsonTypeInfo.Id.CLASS;
_includeAs = JsonTypeInfo.As.PROPERTY;
_typeProperty = propertyName;
}
public DefaultTypeResolverBuilder(PolymorphicTypeValidator subtypeValidator,
DefaultTyping t, JsonTypeInfo.As includeAs,
JsonTypeInfo.Id idType, String propertyName) {
_subtypeValidator = subtypeValidator;
_appliesFor = t;
_idType = idType;
_includeAs = includeAs;
if (propertyName == null) {
propertyName = _idType.getDefaultPropertyName();
}
_typeProperty = propertyName;
}
protected DefaultTypeResolverBuilder(DefaultTypeResolverBuilder base,
Class<?> defaultImpl) {
super(base, defaultImpl);
_subtypeValidator = base._subtypeValidator;
_appliesFor = base._appliesFor;
}
@Override
public DefaultTypeResolverBuilder withDefaultImpl(Class<?> defaultImpl) {
if (_defaultImpl == defaultImpl) {
return this;
}
ClassUtil.verifyMustOverride(DefaultTypeResolverBuilder.class, this, "withDefaultImpl");
// NOTE: MUST create new instance, NOT modify this instance
return new DefaultTypeResolverBuilder(this, defaultImpl);
}
@Override
public PolymorphicTypeValidator subTypeValidator(DatabindContext ctxt) {
return _subtypeValidator;
}
@Override
public TypeDeserializer buildTypeDeserializer(DeserializationContext ctxt,
JavaType baseType, Collection<NamedType> subtypes)
{
return useForType(baseType) ? super.buildTypeDeserializer(ctxt, baseType, subtypes) : null;
}
@Override
public TypeSerializer buildTypeSerializer(SerializationContext ctxt,
JavaType baseType, Collection<NamedType> subtypes)
{
return useForType(baseType) ? super.buildTypeSerializer(ctxt, baseType, subtypes) : null;
}
public DefaultTypeResolverBuilder typeIdVisibility(boolean isVisible) {
_typeIdVisible = isVisible;
return this;
}
/**
* Method called to check if the default type handler should be
* used for given type.
* Note: "natural types" (String, Boolean, Integer, Double) will never
* use typing; that is both due to them being concrete and final,
* and since actual serializers and deserializers will also ignore any
* attempts to enforce typing.
*/
public boolean useForType(JavaType t)
{
// Need to skip primitive types too, regardless
if (t.isPrimitive()) {
return false;
}
switch (_appliesFor) {
case NON_CONCRETE_AND_ARRAYS:
t = _unwrapArrayType(t);
// fall through
case OBJECT_AND_NON_CONCRETE:
// 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling:
t = _unwrapReferenceType(t);
return t.isJavaLangObject()
|| (!t.isConcrete()
// [databind#88] Should not apply to JSON tree models:
&& !TreeNode.class.isAssignableFrom(t.getRawClass()));
case NON_FINAL:
t = _unwrapArrayType(t);
// ReferenceType like Optional also requires similar handling:
t = _unwrapReferenceType(t);
// [databind#88] Should not apply to JSON tree models:
return !t.isFinal() && !TreeNode.class.isAssignableFrom(t.getRawClass());
case NON_FINAL_AND_ENUMS: // since 2.16
t = _unwrapArrayType(t);
// 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling:
t = _unwrapReferenceType(t);
// [databind#88] Should not apply to JSON tree models:
return (!t.isFinal() && !TreeNode.class.isAssignableFrom(t.getRawClass()))
// [databind#3569] Allow use of default typing for Enums
|| t.isEnumType();
default:
case JAVA_LANG_OBJECT:
return t.isJavaLangObject();
}
}
protected JavaType _unwrapArrayType(JavaType t) {
while (t.isArrayType()) {
t = t.getContentType();
}
return t;
}
protected JavaType _unwrapReferenceType(JavaType t) {
while (t.isReferenceType()) {
t = t.getReferencedType();
}
return t;
}
}