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}