package com.fasterxml.jackson.databind.jsontype.impl; import java.util.Collection; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.cfg.MapperConfig; import com.fasterxml.jackson.databind.jsontype.NamedType; import com.fasterxml.jackson.databind.jsontype.TypeDeserializer; import com.fasterxml.jackson.databind.jsontype.TypeIdResolver; import com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder; import com.fasterxml.jackson.databind.jsontype.TypeSerializer; /** * Default {@link TypeResolverBuilder} implementation. * * @author tatu */ public class StdTypeResolverBuilder implements TypeResolverBuilder<StdTypeResolverBuilder> { // Configuration settings: protected JsonTypeInfo.Id _idType; protected JsonTypeInfo.As _includeAs; protected String _typeProperty; /** * Whether type id should be exposed to deserializers or not */ protected boolean _typeIdVisible = false; /** * Default class to use in case type information is not available * or is broken. */ protected Class<?> _defaultImpl; // Objects protected TypeIdResolver _customIdResolver; /* /********************************************************** /* Construction, initialization, actual building /********************************************************** */ public StdTypeResolverBuilder() { } public static StdTypeResolverBuilder noTypeInfoBuilder() { return new StdTypeResolverBuilder().init(JsonTypeInfo.Id.NONE, null); } // @Override public StdTypeResolverBuilder init(JsonTypeInfo.Id idType, TypeIdResolver idRes) { // sanity checks if (idType == null) { throw new IllegalArgumentException("idType can not be null"); } _idType = idType; _customIdResolver = idRes; // Let's also initialize property name as per idType default _typeProperty = idType.getDefaultPropertyName(); return this; } // @Override public TypeSerializer buildTypeSerializer(SerializationConfig config, JavaType baseType, Collection<NamedType> subtypes) { if (_idType == JsonTypeInfo.Id.NONE) { return null; } TypeIdResolver idRes = idResolver(config, baseType, subtypes, true, false); switch (_includeAs) { case WRAPPER_ARRAY: return new AsArrayTypeSerializer(idRes, null); case PROPERTY: return new AsPropertyTypeSerializer(idRes, null, _typeProperty); case WRAPPER_OBJECT: return new AsWrapperTypeSerializer(idRes, null); case EXTERNAL_PROPERTY: return new AsExternalTypeSerializer(idRes, null, _typeProperty); } throw new IllegalStateException("Do not know how to construct standard type serializer for inclusion type: "+_includeAs); } // @Override public TypeDeserializer buildTypeDeserializer(DeserializationConfig config, JavaType baseType, Collection<NamedType> subtypes) { if (_idType == JsonTypeInfo.Id.NONE) { return null; } TypeIdResolver idRes = idResolver(config, baseType, subtypes, false, true); // First, method for converting type info to type id: switch (_includeAs) { case WRAPPER_ARRAY: return new AsArrayTypeDeserializer(baseType, idRes, _typeProperty, _typeIdVisible, _defaultImpl); case PROPERTY: return new AsPropertyTypeDeserializer(baseType, idRes, _typeProperty, _typeIdVisible, _defaultImpl); case WRAPPER_OBJECT: return new AsWrapperTypeDeserializer(baseType, idRes, _typeProperty, _typeIdVisible, _defaultImpl); case EXTERNAL_PROPERTY: return new AsExternalTypeDeserializer(baseType, idRes, _typeProperty, _typeIdVisible, _defaultImpl); } throw new IllegalStateException("Do not know how to construct standard type serializer for inclusion type: "+_includeAs); } /* /********************************************************** /* Construction, configuration /********************************************************** */ // @Override public StdTypeResolverBuilder inclusion(JsonTypeInfo.As includeAs) { if (includeAs == null) { throw new IllegalArgumentException("includeAs can not be null"); } _includeAs = includeAs; return this; } /** * Method for constructing an instance with specified type property name * (property name to use for type id when using "as-property" inclusion). */ // @Override public StdTypeResolverBuilder typeProperty(String typeIdPropName) { // ok to have null/empty; will restore to use defaults if (typeIdPropName == null || typeIdPropName.length() == 0) { typeIdPropName = _idType.getDefaultPropertyName(); } _typeProperty = typeIdPropName; return this; } // @Override public StdTypeResolverBuilder defaultImpl(Class<?> defaultImpl) { _defaultImpl = defaultImpl; return this; } // @Override public StdTypeResolverBuilder typeIdVisibility(boolean isVisible) { _typeIdVisible = isVisible; return this; } /* /********************************************************** /* Accessors /********************************************************** */ public String getTypeProperty() { return _typeProperty; } // @Override public Class<?> getDefaultImpl() { return _defaultImpl; } public boolean isTypeIdVisible() { return _typeIdVisible; } /* /********************************************************** /* Internal methods /********************************************************** */ /** * Helper method that will either return configured custom * type id resolver, or construct a standard resolver * given configuration. */ protected TypeIdResolver idResolver(MapperConfig<?> config, JavaType baseType, Collection<NamedType> subtypes, boolean forSer, boolean forDeser) { // Custom id resolver? if (_customIdResolver != null) { return _customIdResolver; } if (_idType == null) { throw new IllegalStateException("Can not build, 'init()' not yet called"); } switch (_idType) { case CLASS: return new ClassNameIdResolver(baseType, config.getTypeFactory()); case MINIMAL_CLASS: return new MinimalClassNameIdResolver(baseType, config.getTypeFactory()); case NAME: return TypeNameIdResolver.construct(config, baseType, subtypes, forSer, forDeser); case NONE: // hmmh. should never get this far with 'none' return null; case CUSTOM: // need custom resolver... } throw new IllegalStateException("Do not know how to construct standard type id resolver for idType: "+_idType); } }