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