1 package com.fasterxml.jackson.databind.module; 2 3 import java.lang.reflect.Modifier; 4 import java.util.*; 5 6 import com.fasterxml.jackson.databind.AbstractTypeResolver; 7 import com.fasterxml.jackson.databind.BeanDescription; 8 import com.fasterxml.jackson.databind.DeserializationConfig; 9 import com.fasterxml.jackson.databind.JavaType; 10 import com.fasterxml.jackson.databind.type.ClassKey; 11 12 /** 13 * Simple {@link AbstractTypeResolver} implementation, which is 14 * based on static mapping from abstract super types into 15 * sub types (concrete or abstract), but retaining generic 16 * parameterization. 17 * Can be used for things like specifying which implementation of 18 * {@link java.util.Collection} to use: 19 *<pre> 20 * SimpleAbstractTypeResolver resolver = new SimpleAbstractTypeResolver(); 21 * // To make all properties declared as Collection, List, to LinkedList 22 * resolver.addMapping(Collection.class, LinkedList.class); 23 * resolver.addMapping(List.class, LinkedList.class); 24 *</pre> 25 * Can also be used as an alternative to per-class annotations when defining 26 * concrete implementations; however, only works with abstract types (since 27 * this is only called for abstract types) 28 */ 29 public class SimpleAbstractTypeResolver 30 extends AbstractTypeResolver 31 implements java.io.Serializable 32 { 33 private static final long serialVersionUID = 1L; 34 35 /** 36 * Mappings from super types to subtypes 37 */ 38 protected final HashMap<ClassKey,Class<?>> _mappings = new HashMap<ClassKey,Class<?>>(); 39 40 /** 41 * Method for adding a mapping from super type to specific subtype. 42 * Arguments will be checked by method, to ensure that <code>superType</code> 43 * is abstract (since resolver is never called for concrete classes); 44 * as well as to ensure that there is supertype/subtype relationship 45 * (to ensure there won't be cycles during resolution). 46 * 47 * @param superType Abstract type to resolve 48 * @param subType Sub-class of superType, to map superTo to 49 * 50 * @return This resolver, to allow chaining of initializations 51 */ addMapping(Class<T> superType, Class<? extends T> subType)52 public <T> SimpleAbstractTypeResolver addMapping(Class<T> superType, Class<? extends T> subType) 53 { 54 // Sanity checks, just in case someone tries to force typing... 55 if (superType == subType) { 56 throw new IllegalArgumentException("Cannot add mapping from class to itself"); 57 } 58 if (!superType.isAssignableFrom(subType)) { 59 throw new IllegalArgumentException("Cannot add mapping from class "+superType.getName() 60 +" to "+subType.getName()+", as latter is not a subtype of former"); 61 } 62 if (!Modifier.isAbstract(superType.getModifiers())) { 63 throw new IllegalArgumentException("Cannot add mapping from class "+superType.getName() 64 +" since it is not abstract"); 65 } 66 _mappings.put(new ClassKey(superType), subType); 67 return this; 68 } 69 70 @Override findTypeMapping(DeserializationConfig config, JavaType type)71 public JavaType findTypeMapping(DeserializationConfig config, JavaType type) 72 { 73 // this is the main mapping base, so let's 74 Class<?> src = type.getRawClass(); 75 Class<?> dst = _mappings.get(new ClassKey(src)); 76 if (dst == null) { 77 return null; 78 } 79 // 09-Aug-2015, tatu: Instead of direct call via JavaType, better use TypeFactory 80 return config.getTypeFactory().constructSpecializedType(type, dst); 81 } 82 83 @Override 84 @Deprecated resolveAbstractType(DeserializationConfig config, JavaType type)85 public JavaType resolveAbstractType(DeserializationConfig config, JavaType type){ 86 // never materialize anything, so: 87 return null; 88 } 89 90 @Override resolveAbstractType(DeserializationConfig config, BeanDescription typeDesc)91 public JavaType resolveAbstractType(DeserializationConfig config, 92 BeanDescription typeDesc) { 93 // never materialize anything, so: 94 return null; 95 } 96 } 97