blob: 4a8e040f43f2897924eb97453344637ce799a6ce [file] [log] [blame]
package org.codehaus.jackson.map.deser;
import java.util.*;
import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.map.*;
import org.codehaus.jackson.map.type.*;
/**
* Deserializer factory implementation that allows for configuring
* mapping between types and deserializers to use, by using
* multiple types of overrides. Existing mappings established by
* {@link BeanDeserializerFactory} (and its super class,
* {@link BasicDeserializerFactory}) are used if no overrides are
* defined.
*<p>
* Unlike base deserializer factories, this factory is stateful because
* of configuration settings. It is thread-safe, however, as long as
* all configuration as done before using the factory -- a single
* instance can be shared between providers and mappers.
*<p>
* Configurations currently available are:
*<ul>
* <li>Ability to define explicit mappings between simple non-generic
* classes/interfaces and deserializers to use for deserializing
* instance of these classes. Mappings are one-to-one (i.e. there is
* no "generic" variant for handling sub- or super-classes/interfaces).
* </li>
*</ul>
*<p>
* The way custom deserializer factory instances are hooked to
* {@link ObjectMapper} is usually by constructing an instance of
* {@link DeserializerProvider} (most commonly
* {@link StdDeserializerProvider}) with custom deserializer factory,
* and setting {@link ObjectMapper} to use it.
*
* @deprecated Starting with 1.7, functionality of this class has been
* implemented both in base {@link SerializerFactory} (see methods
* like {@link SerializerFactory#withAdditionalSerializers(Serializers)})
* and through new Module API. As such, this class is not the best way
* to add custom functionality, and will likely be removed from 2.0 release
*/
@Deprecated
public class CustomDeserializerFactory
extends BeanDeserializerFactory
{
/*
/**********************************************************
/* Configuration, direct/special mappings
/**********************************************************
*/
/**
* Direct mappings that are used for exact class and interface type
* matches.
*/
protected HashMap<ClassKey,JsonDeserializer<Object>> _directClassMappings = null;
/*
/**********************************************************
/* Configuration: mappings that define "mix-in annotations"
/**********************************************************
*/
/**
* Mapping that defines how to apply mix-in annotations: key is
* the type to received additional annotations, and value is the
* type that has annotations to "mix in".
*<p>
* Annotations associated with the value classes will be used to
* override annotations of the key class, associated with the
* same field or method. They can be further masked by sub-classes:
* you can think of it as injecting annotations between the target
* class and its sub-classes (or interfaces)
*
* @since 1.2
*/
protected HashMap<ClassKey,Class<?>> _mixInAnnotations;
/*
/**********************************************************
/* Life-cycle, constructors
/**********************************************************
*/
public CustomDeserializerFactory() {
this(null);
}
protected CustomDeserializerFactory(Config config)
{
super(config);
}
@Override
public DeserializerFactory withConfig(Config config)
{
// See super-class method for reasons for this check...
if (getClass() != CustomDeserializerFactory.class) {
throw new IllegalStateException("Subtype of CustomDeserializerFactory ("+getClass().getName()
+") has not properly overridden method 'withAdditionalDeserializers': can not instantiate subtype with "
+"additional deserializer definitions");
}
return new CustomDeserializerFactory(config);
}
/*
/**********************************************************
/* Configuration: type-to-serializer mappings
/**********************************************************
*/
/**
* Method used to add a mapping for specific type -- and only that
* type -- to use specified deserializer.
* This means that binding is not used for sub-types.
*<p>
* Note that both class and interfaces can be mapped, since the type
* is derived from method declarations; and hence may be abstract types
* and interfaces. This is different from custom serialization where
* only class types can be directly mapped.
*
* @param forClass Class to deserialize using specific deserializer.
* @param deser Deserializer to use for the class. Declared type for
* deserializer may be more specific (sub-class) than declared class
* to map, since that will still be compatible (deserializer produces
* sub-class which is assignable to field/method)
*/
@SuppressWarnings("unchecked")
public <T> void addSpecificMapping(Class<T> forClass, JsonDeserializer<? extends T> deser)
{
ClassKey key = new ClassKey(forClass);
if (_directClassMappings == null) {
_directClassMappings = new HashMap<ClassKey,JsonDeserializer<Object>>();
}
_directClassMappings.put(key, (JsonDeserializer<Object>)deser);
}
/**
* Method to use for adding mix-in annotations that Class
* <code>classWithMixIns</code> contains into class
* <code>destinationClass</code>. Mixing in is done when introspecting
* class annotations and properties.
* Annotations from <code>classWithMixIns</code> (and its supertypes)
* will <b>override</b>
* anything <code>destinationClass</code> (and its super-types)
* has already.
*
* @param destinationClass Class to modify by adding annotations
* @param classWithMixIns Class that contains annotations to add
*
* @since 1.2
*/
public void addMixInAnnotationMapping(Class<?> destinationClass,
Class<?> classWithMixIns)
{
if (_mixInAnnotations == null) {
_mixInAnnotations = new HashMap<ClassKey,Class<?>>();
}
_mixInAnnotations.put(new ClassKey(destinationClass), classWithMixIns);
}
/*
/**********************************************************
/* DeserializerFactory API
/**********************************************************
*/
@Override
public JsonDeserializer<Object> createBeanDeserializer(DeserializationConfig config, DeserializerProvider p,
JavaType type, BeanProperty property)
throws JsonMappingException
{
Class<?> cls = type.getRawClass();
ClassKey key = new ClassKey(cls);
// Do we have a match?
if (_directClassMappings != null) {
JsonDeserializer<Object> deser = _directClassMappings.get(key);
if (deser != null) {
return deser;
}
}
// If not, let super class do its job
return super.createBeanDeserializer(config, p, type, property);
}
@Override
public JsonDeserializer<?> createArrayDeserializer(DeserializationConfig config, DeserializerProvider p,
ArrayType type, BeanProperty property)
throws JsonMappingException
{
ClassKey key = new ClassKey(type.getRawClass());
if (_directClassMappings != null) {
JsonDeserializer<Object> deser = _directClassMappings.get(key);
if (deser != null) {
return deser;
}
}
return super.createArrayDeserializer(config, p, type, property);
}
//public JsonDeserializer<?> createCollectionDeserializer(...) throws JsonMappingException
@Override
public JsonDeserializer<?> createEnumDeserializer(DeserializationConfig config, DeserializerProvider p,
JavaType enumType, BeanProperty property)
throws JsonMappingException
{
/* Enums can't extend anything; must be a direct
* match, if anything:
* (theoretically they can implement interfaces, but that seems irrelevant)
*/
if (_directClassMappings != null) {
ClassKey key = new ClassKey(enumType.getRawClass());
JsonDeserializer<?> deser = _directClassMappings.get(key);
if (deser != null) {
return deser;
}
}
return super.createEnumDeserializer(config, p, enumType, property);
}
//public JsonDeserializer<?> createMapDeserializer(...) throws JsonMappingException
//public JsonDeserializer<?> createTreeDeserializer(...) throws JsonMappingException
}