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