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