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}