blob: 3701950f5ed8d2e1c33618769da5910aa4b3d13d [file] [log] [blame]
package com.fasterxml.jackson.databind.module;
import java.lang.reflect.Modifier;
import java.util.*;
import com.fasterxml.jackson.databind.AbstractTypeResolver;
import com.fasterxml.jackson.databind.BeanDescription;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.ClassKey;
/**
* Simple {@link AbstractTypeResolver} implementation, which is
* based on static mapping from abstract super types into
* sub types (concrete or abstract), but retaining generic
* parameterization.
* Can be used for things like specifying which implementation of
* {@link java.util.Collection} to use:
*<pre>
* SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver();
* // To make all properties declared as Collection, List, to LinkedList
* resolver.addMapping(Collection.class, LinkedList.class);
* resolver.addMapping(List.class, LinkedList.class);
*</pre>
* Can also be used as an alternative to per-class annotations when defining
* concrete implementations; however, only works with abstract types (since
* this is only called for abstract types)
*/
public class SimpleAbstractTypeResolver
extends AbstractTypeResolver
implements java.io.Serializable
{
private static final long serialVersionUID = 8635483102371490919L;
/**
* Mappings from super types to subtypes
*/
protected final HashMap<ClassKey,Class<?>> _mappings = new HashMap<ClassKey,Class<?>>();
/**
* Method for adding a mapping from super type to specific subtype.
* Arguments will be checked by method, to ensure that <code>superType</code>
* is abstract (since resolver is never called for concrete classes);
* as well as to ensure that there is supertype/subtype relationship
* (to ensure there won't be cycles during resolution).
*
* @param superType Abstract type to resolve
* @param subType Sub-class of superType, to map superTo to
*
* @return This resolver, to allow chaining of initializations
*/
public <T> SimpleAbstractTypeResolver addMapping(Class<T> superType, Class<? extends T> subType)
{
// Sanity checks, just in case someone tries to force typing...
if (superType == subType) {
throw new IllegalArgumentException("Cannot add mapping from class to itself");
}
if (!superType.isAssignableFrom(subType)) {
throw new IllegalArgumentException("Cannot add mapping from class "+superType.getName()
+" to "+subType.getName()+", as latter is not a subtype of former");
}
if (!Modifier.isAbstract(superType.getModifiers())) {
throw new IllegalArgumentException("Cannot add mapping from class "+superType.getName()
+" since it is not abstract");
}
_mappings.put(new ClassKey(superType), subType);
return this;
}
@Override
public JavaType findTypeMapping(DeserializationConfig config, JavaType type)
{
// this is the main mapping base, so let's
Class<?> src = type.getRawClass();
Class<?> dst = _mappings.get(new ClassKey(src));
if (dst == null) {
return null;
}
// 09-Aug-2015, tatu: Instead of direct call via JavaType, better use TypeFactory
return config.getTypeFactory().constructSpecializedType(type, dst);
}
@Override
@Deprecated
public JavaType resolveAbstractType(DeserializationConfig config, JavaType type){
// never materialize anything, so:
return null;
}
@Override
public JavaType resolveAbstractType(DeserializationConfig config,
BeanDescription typeDesc) {
// never materialize anything, so:
return null;
}
}