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: *
 *  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);
 *
* 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 = 1L; /** * Mappings from super types to subtypes */ protected final HashMap> _mappings = new HashMap>(); /** * Method for adding a mapping from super type to specific subtype. * Arguments will be checked by method, to ensure that superType * 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 SimpleAbstractTypeResolver addMapping(Class superType, Class 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; } }