001/* 002 * Copyright (C) 2014 Square, Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.avaje.jsonb.core; 017 018import io.avaje.jsonb.Types; 019 020import java.lang.annotation.Annotation; 021import java.lang.reflect.*; 022import java.util.*; 023 024/** 025 * Utility methods for defining Types. 026 */ 027public final class Util { 028 029 static final Type[] EMPTY_TYPE_ARRAY = new Type[]{}; 030 031 private Util() { 032 } 033 034 /** 035 * Returns an array type whose elements are all instances of {@code componentType}. 036 */ 037 public static GenericArrayType arrayOf(Type elementType) { 038 return new Util.GenericArrayTypeImpl(elementType); 039 } 040 041 /** 042 * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType}. Use this 043 * method if {@code rawType} is not enclosed in another type. 044 */ 045 public static ParameterizedType newParameterizedType(Type rawType, Type... typeArguments) { 046 if (typeArguments.length == 0) { 047 throw new IllegalArgumentException("Missing type arguments for " + rawType); 048 } 049 return new Util.ParameterizedTypeImpl(null, rawType, typeArguments); 050 } 051 052 static boolean typesMatch(Type pattern, Type candidate) { 053 return Util.equals(pattern, candidate); 054 } 055 056 static boolean isAnnotationPresent(Set<? extends Annotation> annotations, Class<? extends Annotation> annotationClass) { 057 if (annotations.isEmpty()) return false; // Save an iterator in the common case. 058 for (Annotation annotation : annotations) { 059 if (annotation.annotationType() == annotationClass) return true; 060 } 061 return false; 062 } 063 064 static Type canonicalizeClass(Class<?> cls) { 065 return cls.isArray() ? new GenericArrayTypeImpl(canonicalize(cls.getComponentType())) : cls; 066 } 067 068 /** 069 * Returns a type that is functionally equal but not necessarily equal according to {@link 070 * Object#equals(Object) Object.equals()}. 071 */ 072 static Type canonicalize(Type type) { 073 if (type instanceof Class) { 074 Class<?> c = (Class<?>) type; 075 return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c; 076 077 } else if (type instanceof ParameterizedType) { 078 if (type instanceof ParameterizedTypeImpl) return type; 079 ParameterizedType p = (ParameterizedType) type; 080 return new ParameterizedTypeImpl( 081 p.getOwnerType(), p.getRawType(), p.getActualTypeArguments()); 082 083 } else if (type instanceof GenericArrayType) { 084 if (type instanceof GenericArrayTypeImpl) return type; 085 GenericArrayType g = (GenericArrayType) type; 086 return new GenericArrayTypeImpl(g.getGenericComponentType()); 087 088 } else if (type instanceof WildcardType) { 089 if (type instanceof WildcardTypeImpl) return type; 090 WildcardType w = (WildcardType) type; 091 return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds()); 092 093 } else { 094 return type; // This type is unsupported! 095 } 096 } 097 098 /** 099 * If type is a "? extends X" wildcard, returns X; otherwise returns type unchanged. 100 */ 101 static Type removeSubtypeWildcard(Type type) { 102 if (!(type instanceof WildcardType)) return type; 103 104 Type[] lowerBounds = ((WildcardType) type).getLowerBounds(); 105 if (lowerBounds.length != 0) return type; 106 107 Type[] upperBounds = ((WildcardType) type).getUpperBounds(); 108 if (upperBounds.length != 1) throw new IllegalArgumentException(); 109 110 return upperBounds[0]; 111 } 112 113 static Type resolve(Type context, Class<?> contextRawType, Type toResolve) { 114 return resolve(context, contextRawType, toResolve, new LinkedHashSet<TypeVariable<?>>()); 115 } 116 117 private static Type resolve( 118 Type context, 119 Class<?> contextRawType, 120 Type toResolve, 121 Collection<TypeVariable<?>> visitedTypeVariables) { 122 // This implementation is made a little more complicated in an attempt to avoid object-creation. 123 while (true) { 124 if (toResolve instanceof TypeVariable) { 125 TypeVariable<?> typeVariable = (TypeVariable<?>) toResolve; 126 if (visitedTypeVariables.contains(typeVariable)) { 127 // cannot reduce due to infinite recursion 128 return toResolve; 129 } else { 130 visitedTypeVariables.add(typeVariable); 131 } 132 toResolve = resolveTypeVariable(context, contextRawType, typeVariable); 133 if (toResolve == typeVariable) return toResolve; 134 135 } else if (toResolve instanceof Class && ((Class<?>) toResolve).isArray()) { 136 Class<?> original = (Class<?>) toResolve; 137 Type componentType = original.getComponentType(); 138 Type newComponentType = 139 resolve(context, contextRawType, componentType, visitedTypeVariables); 140 return componentType == newComponentType ? original : arrayOf(newComponentType); 141 142 } else if (toResolve instanceof GenericArrayType) { 143 GenericArrayType original = (GenericArrayType) toResolve; 144 Type componentType = original.getGenericComponentType(); 145 Type newComponentType = 146 resolve(context, contextRawType, componentType, visitedTypeVariables); 147 return componentType == newComponentType ? original : arrayOf(newComponentType); 148 149 } else if (toResolve instanceof ParameterizedType) { 150 ParameterizedType original = (ParameterizedType) toResolve; 151 Type ownerType = original.getOwnerType(); 152 Type newOwnerType = resolve(context, contextRawType, ownerType, visitedTypeVariables); 153 boolean changed = newOwnerType != ownerType; 154 155 Type[] args = original.getActualTypeArguments(); 156 for (int t = 0, length = args.length; t < length; t++) { 157 Type resolvedTypeArgument = 158 resolve(context, contextRawType, args[t], visitedTypeVariables); 159 if (resolvedTypeArgument != args[t]) { 160 if (!changed) { 161 args = args.clone(); 162 changed = true; 163 } 164 args[t] = resolvedTypeArgument; 165 } 166 } 167 168 return changed 169 ? new ParameterizedTypeImpl(newOwnerType, original.getRawType(), args) 170 : original; 171 172 } else if (toResolve instanceof WildcardType) { 173 WildcardType original = (WildcardType) toResolve; 174 Type[] originalLowerBound = original.getLowerBounds(); 175 Type[] originalUpperBound = original.getUpperBounds(); 176 177 if (originalLowerBound.length == 1) { 178 Type lowerBound = 179 resolve(context, contextRawType, originalLowerBound[0], visitedTypeVariables); 180 if (lowerBound != originalLowerBound[0]) { 181 return supertypeOf(lowerBound); 182 } 183 } else if (originalUpperBound.length == 1) { 184 Type upperBound = 185 resolve(context, contextRawType, originalUpperBound[0], visitedTypeVariables); 186 if (upperBound != originalUpperBound[0]) { 187 return subtypeOf(upperBound); 188 } 189 } 190 return original; 191 192 } else { 193 return toResolve; 194 } 195 } 196 } 197 198 static Type resolveTypeVariable(Type context, Class<?> contextRawType, TypeVariable<?> unknown) { 199 Class<?> declaredByRaw = declaringClassOf(unknown); 200 201 // We can't reduce this further. 202 if (declaredByRaw == null) return unknown; 203 204 Type declaredBy = genericSupertype(context, contextRawType, declaredByRaw); 205 if (declaredBy instanceof ParameterizedType) { 206 int index = indexOf(declaredByRaw.getTypeParameters(), unknown); 207 return ((ParameterizedType) declaredBy).getActualTypeArguments()[index]; 208 } 209 210 return unknown; 211 } 212 213 /** 214 * Returns the generic supertype for {@code supertype}. For example, given a class {@code 215 * IntegerSet}, the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the 216 * result when the supertype is {@code Collection.class} is {@code Collection<Integer>}. 217 */ 218 static Type genericSupertype(Type context, Class<?> rawType, Class<?> toResolve) { 219 if (toResolve == rawType) { 220 return context; 221 } 222 223 // we skip searching through interfaces if unknown is an interface 224 if (toResolve.isInterface()) { 225 Class<?>[] interfaces = rawType.getInterfaces(); 226 for (int i = 0, length = interfaces.length; i < length; i++) { 227 if (interfaces[i] == toResolve) { 228 return rawType.getGenericInterfaces()[i]; 229 } else if (toResolve.isAssignableFrom(interfaces[i])) { 230 return genericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve); 231 } 232 } 233 } 234 235 // check our supertypes 236 if (!rawType.isInterface()) { 237 while (rawType != Object.class) { 238 Class<?> rawSupertype = rawType.getSuperclass(); 239 if (rawSupertype == toResolve) { 240 return rawType.getGenericSuperclass(); 241 } else if (toResolve.isAssignableFrom(rawSupertype)) { 242 return genericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve); 243 } 244 rawType = rawSupertype; 245 } 246 } 247 248 // we can't resolve this further 249 return toResolve; 250 } 251 252 static int hashCodeOrZero(Object o) { 253 return o != null ? o.hashCode() : 0; 254 } 255 256 static String typeToString(Type type) { 257 return type instanceof Class ? ((Class<?>) type).getName() : type.toString(); 258 } 259 260 static int indexOf(Object[] array, Object toFind) { 261 for (int i = 0; i < array.length; i++) { 262 if (toFind.equals(array[i])) return i; 263 } 264 throw new NoSuchElementException(); 265 } 266 267 /** 268 * Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by 269 * a class. 270 */ 271 static Class<?> declaringClassOf(TypeVariable<?> typeVariable) { 272 GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); 273 return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null; 274 } 275 276 static void checkNotPrimitive(Type type) { 277 if ((type instanceof Class<?>) && ((Class<?>) type).isPrimitive()) { 278 throw new IllegalArgumentException("Unexpected primitive " + type + ". Use the boxed type."); 279 } 280 } 281 282 static final class ParameterizedTypeImpl implements ParameterizedType { 283 private final Type ownerType; 284 private final Type rawType; 285 public final Type[] typeArguments; 286 287 public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) { 288 // Require an owner type if the raw type needs it. 289 if (rawType instanceof Class<?>) { 290 Class<?> enclosingClass = ((Class<?>) rawType).getEnclosingClass(); 291 if (ownerType != null) { 292 if (enclosingClass == null || Util.rawType(ownerType) != enclosingClass) { 293 throw new IllegalArgumentException( 294 "unexpected owner type for " + rawType + ": " + ownerType); 295 } 296 } else if (enclosingClass != null) { 297 throw new IllegalArgumentException("unexpected owner type for " + rawType + ": null"); 298 } 299 } 300 301 this.ownerType = ownerType == null ? null : canonicalize(ownerType); 302 this.rawType = canonicalize(rawType); 303 this.typeArguments = typeArguments.clone(); 304 for (int t = 0; t < this.typeArguments.length; t++) { 305 if (this.typeArguments[t] == null) throw new NullPointerException(); 306 checkNotPrimitive(this.typeArguments[t]); 307 this.typeArguments[t] = canonicalize(this.typeArguments[t]); 308 } 309 } 310 311 @Override 312 public Type[] getActualTypeArguments() { 313 return typeArguments.clone(); 314 } 315 316 @Override 317 public Type getRawType() { 318 return rawType; 319 } 320 321 @Override 322 public Type getOwnerType() { 323 return ownerType; 324 } 325 326 @Override 327 public boolean equals(Object other) { 328 return other instanceof ParameterizedType && Util.equals(this, (ParameterizedType) other); 329 } 330 331 @Override 332 public int hashCode() { 333 return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType); 334 } 335 336 @Override 337 public String toString() { 338 StringBuilder result = new StringBuilder(30 * (typeArguments.length + 1)); 339 result.append(typeToString(rawType)); 340 341 if (typeArguments.length == 0) { 342 return result.toString(); 343 } 344 345 result.append("<").append(typeToString(typeArguments[0])); 346 for (int i = 1; i < typeArguments.length; i++) { 347 result.append(", ").append(typeToString(typeArguments[i])); 348 } 349 return result.append(">").toString(); 350 } 351 } 352 353 static final class GenericArrayTypeImpl implements GenericArrayType { 354 private final Type componentType; 355 356 GenericArrayTypeImpl(Type componentType) { 357 this.componentType = canonicalize(componentType); 358 } 359 360 @Override 361 public Type getGenericComponentType() { 362 return componentType; 363 } 364 365 @Override 366 public boolean equals(Object o) { 367 return o instanceof GenericArrayType && Util.equals(this, (GenericArrayType) o); 368 } 369 370 @Override 371 public int hashCode() { 372 return componentType.hashCode(); 373 } 374 375 @Override 376 public String toString() { 377 return typeToString(componentType) + "[]"; 378 } 379 } 380 381 /** 382 * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only 383 * support what the Java 6 language needs - at most one bound. If a lower bound is set, the upper 384 * bound must be Object.class. 385 */ 386 static final class WildcardTypeImpl implements WildcardType { 387 private final Type upperBound; 388 private final Type lowerBound; 389 390 WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) { 391 if (lowerBounds.length > 1) throw new IllegalArgumentException(); 392 if (upperBounds.length != 1) throw new IllegalArgumentException(); 393 394 if (lowerBounds.length == 1) { 395 if (lowerBounds[0] == null) throw new NullPointerException(); 396 checkNotPrimitive(lowerBounds[0]); 397 if (upperBounds[0] != Object.class) throw new IllegalArgumentException(); 398 this.lowerBound = canonicalize(lowerBounds[0]); 399 this.upperBound = Object.class; 400 401 } else { 402 if (upperBounds[0] == null) throw new NullPointerException(); 403 checkNotPrimitive(upperBounds[0]); 404 this.lowerBound = null; 405 this.upperBound = canonicalize(upperBounds[0]); 406 } 407 } 408 409 @Override 410 public Type[] getUpperBounds() { 411 return new Type[]{upperBound}; 412 } 413 414 @Override 415 public Type[] getLowerBounds() { 416 return lowerBound != null ? new Type[]{lowerBound} : EMPTY_TYPE_ARRAY; 417 } 418 419 @Override 420 public boolean equals(Object other) { 421 return other instanceof WildcardType && Util.equals(this, (WildcardType) other); 422 } 423 424 @Override 425 public int hashCode() { 426 // This equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds()). 427 return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode()); 428 } 429 430 @Override 431 public String toString() { 432 if (lowerBound != null) { 433 return "? super " + typeToString(lowerBound); 434 } else if (upperBound == Object.class) { 435 return "?"; 436 } else { 437 return "? extends " + typeToString(upperBound); 438 } 439 } 440 } 441 442 static String typeAnnotatedWithAnnotations(Type type, Set<? extends Annotation> annotations) { 443 return type + (annotations.isEmpty() ? " (with no annotations)" : " annotated " + annotations); 444 } 445 446 /** 447 * Returns a type that represents an unknown type that extends {@code bound}. For example, if 448 * {@code bound} is {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If 449 * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code ? 450 * extends Object}. 451 */ 452 static WildcardType subtypeOf(Type bound) { 453 Type[] upperBounds; 454 if (bound instanceof WildcardType) { 455 upperBounds = ((WildcardType) bound).getUpperBounds(); 456 } else { 457 upperBounds = new Type[]{bound}; 458 } 459 return new Util.WildcardTypeImpl(upperBounds, EMPTY_TYPE_ARRAY); 460 } 461 462 /** 463 * Returns a type that represents an unknown supertype of {@code bound}. For example, if {@code 464 * bound} is {@code String.class}, this returns {@code ? super String}. 465 */ 466 static WildcardType supertypeOf(Type bound) { 467 Type[] lowerBounds; 468 if (bound instanceof WildcardType) { 469 lowerBounds = ((WildcardType) bound).getLowerBounds(); 470 } else { 471 lowerBounds = new Type[]{bound}; 472 } 473 return new Util.WildcardTypeImpl(new Type[]{Object.class}, lowerBounds); 474 } 475 476 477 static Class<?> rawType(Type type) { 478 return Types.rawType(type); 479 } 480 481 /** 482 * Returns the element type of this collection type. 483 * 484 * @throws IllegalArgumentException if this type is not a collection. 485 */ 486 static Type collectionElementType(Type context) { 487 Type collectionType = supertype(context, Collection.class, Collection.class); 488 if (collectionType instanceof WildcardType) { 489 collectionType = ((WildcardType) collectionType).getUpperBounds()[0]; 490 } 491 if (collectionType instanceof ParameterizedType) { 492 return ((ParameterizedType) collectionType).getActualTypeArguments()[0]; 493 } 494 return Object.class; 495 } 496 497 /** 498 * Returns true if {@code a} and {@code b} are equal. 499 */ 500 static boolean equals(Type a, Type b) { 501 if (a == b) { 502 return true; // Also handles (a == null && b == null). 503 504 } else if (a instanceof Class) { 505 if (b instanceof GenericArrayType) { 506 return equals(((Class<?>) a).getComponentType(), ((GenericArrayType) b).getGenericComponentType()); 507 } 508 return a.equals(b); // Class already specifies equals(). 509 510 } else if (a instanceof ParameterizedType) { 511 if (!(b instanceof ParameterizedType)) return false; 512 ParameterizedType pa = (ParameterizedType) a; 513 ParameterizedType pb = (ParameterizedType) b; 514 Type[] aTypeArguments = 515 pa instanceof Util.ParameterizedTypeImpl 516 ? ((Util.ParameterizedTypeImpl) pa).typeArguments 517 : pa.getActualTypeArguments(); 518 Type[] bTypeArguments = 519 pb instanceof Util.ParameterizedTypeImpl 520 ? ((Util.ParameterizedTypeImpl) pb).typeArguments 521 : pb.getActualTypeArguments(); 522 return equals(pa.getOwnerType(), pb.getOwnerType()) 523 && pa.getRawType().equals(pb.getRawType()) 524 && Arrays.equals(aTypeArguments, bTypeArguments); 525 526 } else if (a instanceof GenericArrayType) { 527 if (b instanceof Class) { 528 return equals(((Class<?>) b).getComponentType(), ((GenericArrayType) a).getGenericComponentType()); 529 } 530 if (!(b instanceof GenericArrayType)) return false; 531 GenericArrayType ga = (GenericArrayType) a; 532 GenericArrayType gb = (GenericArrayType) b; 533 return equals(ga.getGenericComponentType(), gb.getGenericComponentType()); 534 535 } else if (a instanceof WildcardType) { 536 if (!(b instanceof WildcardType)) return false; 537 WildcardType wa = (WildcardType) a; 538 WildcardType wb = (WildcardType) b; 539 return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds()) 540 && Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds()); 541 542 } else if (a instanceof TypeVariable) { 543 if (!(b instanceof TypeVariable)) return false; 544 TypeVariable<?> va = (TypeVariable<?>) a; 545 TypeVariable<?> vb = (TypeVariable<?>) b; 546 return va.getGenericDeclaration() == vb.getGenericDeclaration() 547 && va.getName().equals(vb.getName()); 548 549 } else { 550 // This isn't a supported type. 551 return false; 552 } 553 } 554 555 /** 556 * Returns a two element array containing this map's key and value types in positions 0 and 1 557 * respectively. 558 */ 559 static Type mapValueType(Type context, Class<?> contextRawType) { 560 // Work around a problem with the declaration of java.util.Properties. That class should extend 561 // Hashtable<String, String>, but it's declared to extend Hashtable<Object, Object>. 562 if (context == Properties.class) { 563 return String.class; 564 } 565 Type mapType = supertype(context, contextRawType, Map.class); 566 if (mapType instanceof ParameterizedType) { 567 ParameterizedType mapParameterizedType = (ParameterizedType) mapType; 568 return mapParameterizedType.getActualTypeArguments()[1]; 569 } 570 return Object.class; 571 } 572 573 /** 574 * Returns the generic form of {@code supertype}. For example, if this is {@code 575 * ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code 576 * Iterable.class}. 577 * 578 * @param supertype a superclass of, or interface implemented by, this. 579 */ 580 static Type supertype(Type context, Class<?> contextRawType, Class<?> supertype) { 581 if (!supertype.isAssignableFrom(contextRawType)) throw new IllegalArgumentException(); 582 return resolve(context, contextRawType, genericSupertype(context, contextRawType, supertype)); 583 } 584 585 /** 586 * Returns the element type of {@code type} if it is an array type, or null if it is not an array 587 * type. 588 */ 589 static Type arrayComponentType(Type type) { 590 if (type instanceof GenericArrayType) { 591 return ((GenericArrayType) type).getGenericComponentType(); 592 } else if (type instanceof Class) { 593 return ((Class<?>) type).getComponentType(); 594 } else { 595 return null; 596 } 597 } 598}