1 package com.fasterxml.jackson.databind.type; 2 3 import java.io.IOException; 4 import java.util.*; 5 6 import com.fasterxml.jackson.core.JsonGenerator; 7 import com.fasterxml.jackson.core.JsonProcessingException; 8 import com.fasterxml.jackson.core.JsonToken; 9 import com.fasterxml.jackson.core.type.WritableTypeId; 10 import com.fasterxml.jackson.databind.*; 11 import com.fasterxml.jackson.databind.jsontype.TypeSerializer; 12 13 public abstract class TypeBase 14 extends JavaType 15 implements JsonSerializable 16 { 17 private static final long serialVersionUID = 1; 18 19 private final static TypeBindings NO_BINDINGS = TypeBindings.emptyBindings(); 20 private final static JavaType[] NO_TYPES = new JavaType[0]; 21 22 protected final JavaType _superClass; 23 24 protected final JavaType[] _superInterfaces; 25 26 /** 27 * Bindings in effect for this type instance; possibly empty. 28 * Needed when resolving types declared in members of this type 29 * (if any). 30 * 31 * @since 2.7 32 */ 33 protected final TypeBindings _bindings; 34 35 /** 36 * Lazily initialized external representation of the type 37 */ 38 volatile transient String _canonicalName; 39 40 /** 41 * Main constructor to use by extending classes. 42 */ TypeBase(Class<?> raw, TypeBindings bindings, JavaType superClass, JavaType[] superInts, int hash, Object valueHandler, Object typeHandler, boolean asStatic)43 protected TypeBase(Class<?> raw, TypeBindings bindings, JavaType superClass, JavaType[] superInts, 44 int hash, 45 Object valueHandler, Object typeHandler, boolean asStatic) 46 { 47 super(raw, hash, valueHandler, typeHandler, asStatic); 48 _bindings = (bindings == null) ? NO_BINDINGS : bindings; 49 _superClass = superClass; 50 _superInterfaces = superInts; 51 } 52 53 /** 54 * Copy-constructor used when refining/upgrading type instances. 55 * 56 * @since 2.7 57 */ TypeBase(TypeBase base)58 protected TypeBase(TypeBase base) { 59 super(base); 60 _superClass = base._superClass; 61 _superInterfaces = base._superInterfaces; 62 _bindings = base._bindings; 63 } 64 65 @Override toCanonical()66 public String toCanonical() 67 { 68 String str = _canonicalName; 69 if (str == null) { 70 str = buildCanonicalName(); 71 } 72 return str; 73 } 74 buildCanonicalName()75 protected String buildCanonicalName() { 76 return _class.getName(); 77 } 78 79 @Override getGenericSignature(StringBuilder sb)80 public abstract StringBuilder getGenericSignature(StringBuilder sb); 81 82 @Override getErasedSignature(StringBuilder sb)83 public abstract StringBuilder getErasedSignature(StringBuilder sb); 84 85 @Override getBindings()86 public TypeBindings getBindings() { 87 return _bindings; 88 } 89 90 @Override containedTypeCount()91 public int containedTypeCount() { 92 return _bindings.size(); 93 } 94 95 @Override containedType(int index)96 public JavaType containedType(int index) { 97 return _bindings.getBoundType(index); 98 } 99 100 @Override 101 @Deprecated containedTypeName(int index)102 public String containedTypeName(int index) { 103 return _bindings.getBoundName(index); 104 } 105 106 @Override getSuperClass()107 public JavaType getSuperClass() { 108 return _superClass; 109 } 110 111 @Override getInterfaces()112 public List<JavaType> getInterfaces() { 113 if (_superInterfaces == null) { 114 return Collections.emptyList(); 115 } 116 switch (_superInterfaces.length) { 117 case 0: 118 return Collections.emptyList(); 119 case 1: 120 return Collections.singletonList(_superInterfaces[0]); 121 } 122 return Arrays.asList(_superInterfaces); 123 } 124 125 @Override findSuperType(Class<?> rawTarget)126 public final JavaType findSuperType(Class<?> rawTarget) 127 { 128 if (rawTarget == _class) { 129 return this; 130 } 131 // Check super interfaces first: 132 if (rawTarget.isInterface() && (_superInterfaces != null)) { 133 for (int i = 0, count = _superInterfaces.length; i < count; ++i) { 134 JavaType type = _superInterfaces[i].findSuperType(rawTarget); 135 if (type != null) { 136 return type; 137 } 138 } 139 } 140 // and if not found, super class and its supertypes 141 if (_superClass != null) { 142 JavaType type = _superClass.findSuperType(rawTarget); 143 if (type != null) { 144 return type; 145 } 146 } 147 return null; 148 } 149 150 @Override findTypeParameters(Class<?> expType)151 public JavaType[] findTypeParameters(Class<?> expType) 152 { 153 JavaType match = findSuperType(expType); 154 if (match == null) { 155 return NO_TYPES; 156 } 157 return match.getBindings().typeParameterArray(); 158 } 159 160 /* 161 /********************************************************** 162 /* JsonSerializable base implementation 163 /********************************************************** 164 */ 165 166 @Override serializeWithType(JsonGenerator g, SerializerProvider provider, TypeSerializer typeSer)167 public void serializeWithType(JsonGenerator g, SerializerProvider provider, 168 TypeSerializer typeSer) 169 throws IOException 170 { 171 WritableTypeId typeIdDef = new WritableTypeId(this, JsonToken.VALUE_STRING); 172 typeSer.writeTypePrefix(g, typeIdDef); 173 this.serialize(g, provider); 174 typeSer.writeTypeSuffix(g, typeIdDef); 175 } 176 177 @Override serialize(JsonGenerator gen, SerializerProvider provider)178 public void serialize(JsonGenerator gen, SerializerProvider provider) 179 throws IOException, JsonProcessingException 180 { 181 gen.writeString(toCanonical()); 182 } 183 184 /* 185 /********************************************************** 186 /* Methods for sub-classes to use 187 /********************************************************** 188 */ 189 190 /** 191 * @param trailingSemicolon Whether to add trailing semicolon for non-primitive 192 * (reference) types or not 193 */ _classSignature(Class<?> cls, StringBuilder sb, boolean trailingSemicolon)194 protected static StringBuilder _classSignature(Class<?> cls, StringBuilder sb, 195 boolean trailingSemicolon) 196 { 197 if (cls.isPrimitive()) { 198 if (cls == Boolean.TYPE) { 199 sb.append('Z'); 200 } else if (cls == Byte.TYPE) { 201 sb.append('B'); 202 } 203 else if (cls == Short.TYPE) { 204 sb.append('S'); 205 } 206 else if (cls == Character.TYPE) { 207 sb.append('C'); 208 } 209 else if (cls == Integer.TYPE) { 210 sb.append('I'); 211 } 212 else if (cls == Long.TYPE) { 213 sb.append('J'); 214 } 215 else if (cls == Float.TYPE) { 216 sb.append('F'); 217 } 218 else if (cls == Double.TYPE) { 219 sb.append('D'); 220 } 221 else if (cls == Void.TYPE) { 222 sb.append('V'); 223 } else { 224 throw new IllegalStateException("Unrecognized primitive type: "+cls.getName()); 225 } 226 } else { 227 sb.append('L'); 228 String name = cls.getName(); 229 for (int i = 0, len = name.length(); i < len; ++i) { 230 char c = name.charAt(i); 231 if (c == '.') c = '/'; 232 sb.append(c); 233 } 234 if (trailingSemicolon) { 235 sb.append(';'); 236 } 237 } 238 return sb; 239 } 240 241 /** 242 * Internal helper method used to figure out nominal super-class for 243 * deprecated factory methods / constructors, where we are not given 244 * properly resolved supertype hierarchy. 245 * Will basically give `JavaType` for `java.lang.Object` for classes 246 * other than `java.lafgn.Object`; null for others. 247 * 248 * @since 2.7 249 */ _bogusSuperClass(Class<?> cls)250 protected static JavaType _bogusSuperClass(Class<?> cls) { 251 Class<?> parent = cls.getSuperclass(); 252 if (parent == null) { 253 return null; 254 } 255 return TypeFactory.unknownType(); 256 } 257 } 258