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>
* In near future, following features are planned to be added:
*<ul>
* <li>Ability to define "mix-in annotations": associations between types
* (classes, interfaces) to deserialize, and a "mix-in" type which will
* be used so that all of its annotations are added to the deserialized
* type. Mixed-in annotations have priority over annotations that the
* deserialized type has. In effect this allows for overriding annotations
* types have; this is useful when type definition itself can not be
* modified
* </li>
*/
public class CustomDeserializerFactory
extends BeanDeserializerFactory
{
/*
////////////////////////////////////////////////////
// Configuration, direct/special mappings
////////////////////////////////////////////////////
*/
/**
* Direct mappings that are used for exact class and interface type
* matches.
*/
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
*/
HashMap<ClassKey,Class<?>> _mixInAnnotations;
/*
////////////////////////////////////////////////////
// Life-cycle, constructors
////////////////////////////////////////////////////
*/
public CustomDeserializerFactory() { super(); }
/*
////////////////////////////////////////////////////
// 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, JavaType type, DeserializerProvider p)
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, type, p);
}
//public JsonDeserializer<?> createArrayDeserializer(DeserializationConfig config, ArrayType type, DeserializerProvider p) throws JsonMappingException
//public JsonDeserializer<?> createCollectionDeserializer(DeserializationConfig config, CollectionType type, DeserializerProvider p) throws JsonMappingException
@Override
public JsonDeserializer<?> createEnumDeserializer(DeserializationConfig config, Class<?> enumClass, DeserializerProvider p) throws JsonMappingException
{
/* Enums can't extend anything (or implement); must be a direct
* match, if anything:
*/
if (_directClassMappings != null) {
ClassKey key = new ClassKey(enumClass);
JsonDeserializer<?> deser = _directClassMappings.get(key);
if (deser != null) {
return deser;
}
}
return super.createEnumDeserializer(config, enumClass, p);
}
//public JsonDeserializer<?> createMapDeserializer(DeserializationConfig config, MapType type, DeserializerProvider p) throws JsonMappingException
//public JsonDeserializer<?> createTreeDeserializer(DeserializationConfig config, Class<? extends JsonNode> nodeClass, DeserializerProvider p) throws JsonMappingException
}