1 /*
   2  * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.reflect.annotation;
  27 
  28 import java.lang.annotation.*;
  29 import java.lang.reflect.*;
  30 import java.util.ArrayList;
  31 import java.util.Arrays;
  32 import java.util.List;
  33 import java.util.Map;
  34 import java.util.Objects;
  35 import java.util.StringJoiner;
  36 import java.util.stream.Stream;
  37 import java.util.stream.Collectors;
  38 
  39 import static sun.reflect.annotation.TypeAnnotation.*;
  40 
  41 public final class AnnotatedTypeFactory {
  42     /**
  43      * Create an AnnotatedType.
  44      *
  45      * @param type the type this AnnotatedType corresponds to
  46      * @param currentLoc the location this AnnotatedType corresponds to
  47      * @param actualTypeAnnos the type annotations this AnnotatedType has
  48      * @param allOnSameTarget all type annotation on the same TypeAnnotationTarget
  49      *                          as the AnnotatedType being built
  50      * @param decl the declaration having the type use this AnnotatedType
  51      *                          corresponds to
  52      */
  53     public static AnnotatedType buildAnnotatedType(Type type,
  54             LocationInfo currentLoc,
  55             TypeAnnotation[] actualTypeAnnos,
  56             TypeAnnotation[] allOnSameTarget,
  57             AnnotatedElement decl) {
  58         if (type == null) {
  59             return EMPTY_ANNOTATED_TYPE;
  60         }
  61         if (isArray(type))
  62             return new AnnotatedArrayTypeImpl(type,
  63                     currentLoc,
  64                     actualTypeAnnos,
  65                     allOnSameTarget,
  66                     decl);
  67         if (type instanceof Class) {
  68             return new AnnotatedTypeBaseImpl(type,
  69                     currentLoc,
  70                     actualTypeAnnos,
  71                     allOnSameTarget,
  72                     decl);
  73         } else if (type instanceof TypeVariable) {
  74             return new AnnotatedTypeVariableImpl((TypeVariable)type,
  75                     currentLoc,
  76                     actualTypeAnnos,
  77                     allOnSameTarget,
  78                     decl);
  79         } else if (type instanceof ParameterizedType) {
  80             return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
  81                     currentLoc,
  82                     actualTypeAnnos,
  83                     allOnSameTarget,
  84                     decl);
  85         } else if (type instanceof WildcardType) {
  86             return new AnnotatedWildcardTypeImpl((WildcardType) type,
  87                     currentLoc,
  88                     actualTypeAnnos,
  89                     allOnSameTarget,
  90                     decl);
  91         }
  92         throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
  93     }
  94 
  95     public static LocationInfo nestingForType(Type type, LocationInfo addTo) {
  96         if (isArray(type))
  97             return addTo;
  98         if (type instanceof Class) {
  99             Class<?> clz = (Class)type;
 100             if (clz.getEnclosingClass() == null)
 101                 return addTo;
 102             if (Modifier.isStatic(clz.getModifiers()))
 103                 return addTo;
 104             return nestingForType(clz.getEnclosingClass(), addTo.pushInner());
 105         } else if (type instanceof ParameterizedType) {
 106             ParameterizedType t = (ParameterizedType)type;
 107             if (t.getOwnerType() == null)
 108                 return addTo;
 109             if (t.getRawType() instanceof Class
 110                     && Modifier.isStatic(((Class) t.getRawType()).getModifiers()))
 111                 return addTo;
 112             return nestingForType(t.getOwnerType(), addTo.pushInner());
 113         }
 114         return addTo;
 115     }
 116 
 117     private static boolean isArray(Type t) {
 118         if (t instanceof Class) {
 119             Class<?> c = (Class)t;
 120             if (c.isArray())
 121                 return true;
 122         } else if (t instanceof GenericArrayType) {
 123             return true;
 124         }
 125         return false;
 126     }
 127 
 128     static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0];
 129     static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
 130             EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, null);
 131     static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
 132 
 133     /*
 134      * Note that if additional subclasses of AnnotatedTypeBaseImpl are
 135      * added, the equals methods of AnnotatedTypeBaseImpl will need to
 136      * be updated to properly implement the equals contract.
 137      */
 138 
 139     private static class AnnotatedTypeBaseImpl implements AnnotatedType {
 140         private final Type type;
 141         private final AnnotatedElement decl;
 142         private final LocationInfo location;
 143         private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
 144         private final Map<Class <? extends Annotation>, Annotation> annotations;
 145 
 146         AnnotatedTypeBaseImpl(Type type, LocationInfo location,
 147                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 148                 AnnotatedElement decl) {
 149             this.type = type;
 150             this.decl = decl;
 151             this.location = location;
 152             this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
 153             this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations));
 154         }
 155 
 156         // AnnotatedElement
 157         @Override
 158         public final Annotation[] getAnnotations() {
 159             return getDeclaredAnnotations();
 160         }
 161 
 162         @Override
 163         public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
 164             return getDeclaredAnnotation(annotation);
 165         }
 166 
 167         @Override
 168         public final <T extends Annotation> T[] getAnnotationsByType(Class<T> annotation) {
 169             return getDeclaredAnnotationsByType(annotation);
 170         }
 171 
 172         @Override
 173         public final Annotation[] getDeclaredAnnotations() {
 174             return annotations.values().toArray(new Annotation[0]);
 175         }
 176 
 177         @Override
 178         @SuppressWarnings("unchecked")
 179         public final <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
 180             return (T)annotations.get(annotation);
 181         }
 182 
 183         @Override
 184         public final <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotation) {
 185             return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotations, annotation);
 186         }
 187 
 188         // AnnotatedType
 189         @Override
 190         public final Type getType() {
 191             return type;
 192         }
 193 
 194         @Override
 195         public AnnotatedType getAnnotatedOwnerType() {
 196             if (!(type instanceof Class<?>))
 197                 throw new IllegalStateException("Can't compute owner");
 198 
 199             Class<?> nested = (Class<?>)type;
 200             Class<?> owner = nested.getDeclaringClass();
 201             if (owner == null) // top-level, local or anonymous
 202                 return null;
 203             if (nested.isPrimitive() || nested == Void.TYPE)
 204                 return null;
 205 
 206             LocationInfo outerLoc = getLocation().popLocation((byte)1);
 207             if (outerLoc == null) {
 208               return buildAnnotatedType(owner, LocationInfo.BASE_LOCATION,
 209                       EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, getDecl());
 210             }
 211             TypeAnnotation[]all = getTypeAnnotations();
 212             List<TypeAnnotation> l = new ArrayList<>(all.length);
 213 
 214             for (TypeAnnotation t : all)
 215                 if (t.getLocationInfo().isSameLocationInfo(outerLoc))
 216                     l.add(t);
 217 
 218             return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
 219 
 220         }
 221 
 222         @Override // java.lang.Object
 223         public String toString() {
 224             // Reusable toString implementation, but needs to be
 225             // specialized for quirks of arrays and interior types of
 226             // wildcards, etc.
 227             return annotationsToString(getAnnotations(), false) +
 228                 ((type instanceof Class) ? type.getTypeName(): type.toString());
 229         }
 230 
 231         protected String annotationsToString(Annotation[] annotations, boolean leadingSpace) {
 232             if (annotations != null && annotations.length > 0) {
 233                 StringBuffer sb = new StringBuffer();
 234 
 235                 sb.append(Stream.of(annotations).
 236                           map(Annotation::toString).
 237                           collect(Collectors.joining(" ")));
 238 
 239                 if (leadingSpace)
 240                     sb.insert(0, " ");
 241                 else
 242                     sb.append(" ");
 243 
 244                 return sb.toString();
 245             } else {
 246                 return "";
 247             }
 248         }
 249 
 250         protected boolean equalsTypeAndAnnotations(AnnotatedType that) {
 251             return getType().equals(that.getType()) &&
 252                 // Treat ordering of annotations as significant
 253                 Arrays.equals(getAnnotations(), that.getAnnotations()) &&
 254                 Objects.equals(getAnnotatedOwnerType(), that.getAnnotatedOwnerType());
 255         }
 256 
 257         int baseHashCode() {
 258             return type.hashCode() ^
 259                 // Acceptable to use Objects.hash rather than
 260                 // Arrays.deepHashCode since the elements of the array
 261                 // are not themselves arrays.
 262                 Objects.hash((Object[])getAnnotations()) ^
 263                 Objects.hash(getAnnotatedOwnerType());
 264         }
 265 
 266         @Override
 267         public boolean equals(Object o) {
 268             if (o instanceof AnnotatedType &&
 269                 !(o instanceof AnnotatedArrayType) &&
 270                 !(o instanceof AnnotatedTypeVariable) &&
 271                 !(o instanceof AnnotatedParameterizedType) &&
 272                 !(o instanceof AnnotatedWildcardType)) {
 273                 AnnotatedType that = (AnnotatedType) o;
 274                 return equalsTypeAndAnnotations(that);
 275             } else {
 276                 return false;
 277             }
 278         }
 279 
 280         @Override
 281         public int hashCode() {
 282             return baseHashCode();
 283         }
 284 
 285         // Implementation details
 286         final LocationInfo getLocation() {
 287             return location;
 288         }
 289         final TypeAnnotation[] getTypeAnnotations() {
 290             return allOnSameTargetTypeAnnotations;
 291         }
 292         final AnnotatedElement getDecl() {
 293             return decl;
 294         }
 295     }
 296 
 297     private static final class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
 298         AnnotatedArrayTypeImpl(Type type, LocationInfo location,
 299                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 300                 AnnotatedElement decl) {
 301             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 302         }
 303 
 304         @Override
 305         public AnnotatedType getAnnotatedGenericComponentType() {
 306             Type t = getComponentType();
 307             return AnnotatedTypeFactory.buildAnnotatedType(t,
 308                     nestingForType(t, getLocation().pushArray()),
 309                     getTypeAnnotations(),
 310                     getTypeAnnotations(),
 311                     getDecl());
 312         }
 313 
 314         @Override
 315         public AnnotatedType getAnnotatedOwnerType() {
 316             return null;
 317         }
 318 
 319         private Type getComponentType() {
 320             Type t = getType();
 321             if (t instanceof Class) {
 322                 Class<?> c = (Class)t;
 323                 return c.getComponentType();
 324             }
 325             return ((GenericArrayType)t).getGenericComponentType();
 326         }
 327 
 328         @Override
 329         public String toString() {
 330             // To annotate the full type of an array, the annotations
 331             // are placed between the type and the brackets. For
 332             // example, to annotate an array of Strings, the syntax used is
 333             //
 334             // String @TypeAnnotation []
 335             //
 336             // and *not*
 337             //
 338             // @TypeAnnotation String[].
 339             //
 340             // The toString output should strive to be reusable in
 341             // source code. Therefore, the general logic of putting
 342             // the annotations before a textual representation of the
 343             // type need to be overridden for arrays.
 344             StringBuilder sb = new StringBuilder();
 345 
 346             AnnotatedType componentType = this;
 347             while (componentType instanceof AnnotatedArrayType) {
 348                 AnnotatedArrayType annotatedArrayType = (AnnotatedArrayType) componentType;
 349                 sb.append(annotationsToString(annotatedArrayType.getAnnotations(), true) + "[]");
 350                 componentType = annotatedArrayType.getAnnotatedGenericComponentType();
 351             }
 352 
 353             sb.insert(0, componentType.toString());
 354             return sb.toString();
 355         }
 356 
 357         @Override
 358         public boolean equals(Object o) {
 359             if (o instanceof AnnotatedArrayType) {
 360                 AnnotatedArrayType that = (AnnotatedArrayType) o;
 361                 return equalsTypeAndAnnotations(that) &&
 362                     Objects.equals(getAnnotatedGenericComponentType(),
 363                                    that.getAnnotatedGenericComponentType());
 364             } else {
 365                 return false;
 366             }
 367         }
 368 
 369         @Override
 370         public int hashCode() {
 371             return baseHashCode() ^ getAnnotatedGenericComponentType().hashCode();
 372         }
 373     }
 374 
 375     private static final class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
 376         AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
 377                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 378                 AnnotatedElement decl) {
 379             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 380         }
 381 
 382         @Override
 383         public AnnotatedType[] getAnnotatedBounds() {
 384             return getTypeVariable().getAnnotatedBounds();
 385         }
 386 
 387         @Override
 388         public AnnotatedType getAnnotatedOwnerType() {
 389             return null;
 390         }
 391 
 392         private TypeVariable<?> getTypeVariable() {
 393             return (TypeVariable)getType();
 394         }
 395 
 396         // For toString, the declaration of a type variable should
 397         // including information about its bounds, etc. However, the
 398         // use of a type variable should not. For that reason, it is
 399         // acceptable for the toString implementation of
 400         // AnnotatedTypeVariableImpl to use the inherited
 401         // implementation from AnnotatedTypeBaseImpl.
 402 
 403         @Override
 404         public boolean equals(Object o) {
 405             if (o instanceof AnnotatedTypeVariable) {
 406                 AnnotatedTypeVariable that = (AnnotatedTypeVariable) o;
 407                 return equalsTypeAndAnnotations(that) &&
 408                     Arrays.equals(getAnnotatedBounds(), that.getAnnotatedBounds());
 409             } else {
 410                 return false;
 411             }
 412         }
 413 
 414         @Override
 415         public int hashCode() {
 416             return baseHashCode() ^
 417                 Objects.hash((Object[])getAnnotatedBounds());
 418         }
 419     }
 420 
 421     private static final class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl
 422             implements AnnotatedParameterizedType {
 423         AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
 424                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 425                 AnnotatedElement decl) {
 426             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 427         }
 428 
 429         @Override
 430         public AnnotatedType[] getAnnotatedActualTypeArguments() {
 431             Type[] arguments = getParameterizedType().getActualTypeArguments();
 432             AnnotatedType[] res = new AnnotatedType[arguments.length];
 433             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 434             int initialCapacity = getTypeAnnotations().length;
 435             for (int i = 0; i < res.length; i++) {
 436                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 437                 LocationInfo newLoc = nestingForType(arguments[i], getLocation().pushTypeArg((byte)i));
 438                 for (TypeAnnotation t : getTypeAnnotations())
 439                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 440                         l.add(t);
 441                 res[i] = buildAnnotatedType(arguments[i],
 442                         newLoc,
 443                         l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
 444                         getTypeAnnotations(),
 445                         getDecl());
 446             }
 447             return res;
 448         }
 449 
 450         @Override
 451         public AnnotatedType getAnnotatedOwnerType() {
 452             Type owner = getParameterizedType().getOwnerType();
 453             if (owner == null)
 454                 return null;
 455 
 456             LocationInfo outerLoc = getLocation().popLocation((byte)1);
 457             if (outerLoc == null) {
 458               return buildAnnotatedType(owner, LocationInfo.BASE_LOCATION,
 459                       EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, getDecl());
 460             }
 461             TypeAnnotation[]all = getTypeAnnotations();
 462             List<TypeAnnotation> l = new ArrayList<>(all.length);
 463 
 464             for (TypeAnnotation t : all)
 465                 if (t.getLocationInfo().isSameLocationInfo(outerLoc))
 466                     l.add(t);
 467 
 468             return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
 469         }
 470 
 471         private ParameterizedType getParameterizedType() {
 472             return (ParameterizedType)getType();
 473         }
 474 
 475         @Override
 476         public String toString() {
 477             StringBuilder sb = new StringBuilder();
 478             sb.append(annotationsToString(getAnnotations(), false));
 479 
 480             Type t = getParameterizedType().getRawType();
 481             sb.append(t.getTypeName());
 482 
 483             AnnotatedType[] typeArgs = getAnnotatedActualTypeArguments();
 484             if (typeArgs.length > 0) {
 485                 sb.append(Stream.of(typeArgs).map(AnnotatedType::toString).
 486                           collect(Collectors.joining(", ", "<", ">")));
 487             }
 488 
 489             return sb.toString();
 490         }
 491 
 492         @Override
 493         public boolean equals(Object o) {
 494             if (o instanceof AnnotatedParameterizedType) {
 495                 AnnotatedParameterizedType that = (AnnotatedParameterizedType) o;
 496                 return equalsTypeAndAnnotations(that) &&
 497                     Arrays.equals(getAnnotatedActualTypeArguments(), that.getAnnotatedActualTypeArguments());
 498             } else {
 499                 return false;
 500             }
 501         }
 502 
 503         @Override
 504         public int hashCode() {
 505             return baseHashCode() ^
 506                 Objects.hash((Object[])getAnnotatedActualTypeArguments());
 507         }
 508     }
 509 
 510     private static final class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
 511         private final boolean hasUpperBounds;
 512         AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
 513                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 514                 AnnotatedElement decl) {
 515             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 516             hasUpperBounds = (type.getLowerBounds().length == 0);
 517         }
 518 
 519         @Override
 520         public AnnotatedType[] getAnnotatedUpperBounds() {
 521             if (!hasUpperBounds()) {
 522                 return new AnnotatedType[] { buildAnnotatedType(Object.class,
 523                         LocationInfo.BASE_LOCATION,
 524                         EMPTY_TYPE_ANNOTATION_ARRAY,
 525                         EMPTY_TYPE_ANNOTATION_ARRAY,
 526                         null)
 527                 };
 528             }
 529             return getAnnotatedBounds(getWildcardType().getUpperBounds());
 530         }
 531 
 532         @Override
 533         public AnnotatedType[] getAnnotatedLowerBounds() {
 534             if (hasUpperBounds)
 535                 return new AnnotatedType[0];
 536             return getAnnotatedBounds(getWildcardType().getLowerBounds());
 537         }
 538 
 539         @Override
 540         public AnnotatedType getAnnotatedOwnerType() {
 541             return null;
 542         }
 543 
 544         private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
 545             AnnotatedType[] res = new AnnotatedType[bounds.length];
 546             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 547             int initialCapacity = getTypeAnnotations().length;
 548             for (int i = 0; i < res.length; i++) {
 549                 LocationInfo newLoc = nestingForType(bounds[i], getLocation().pushWildcard());
 550                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 551                 for (TypeAnnotation t : getTypeAnnotations())
 552                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 553                         l.add(t);
 554                 res[i] = buildAnnotatedType(bounds[i],
 555                         newLoc,
 556                         l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
 557                         getTypeAnnotations(),
 558                         getDecl());
 559             }
 560             return res;
 561         }
 562 
 563         private WildcardType getWildcardType() {
 564             return (WildcardType)getType();
 565         }
 566 
 567         private boolean hasUpperBounds() {
 568             return hasUpperBounds;
 569         }
 570 
 571         @Override
 572         public String toString() {
 573             StringBuilder sb = new StringBuilder();
 574             sb.append(annotationsToString(getAnnotations(), false));
 575             sb.append("?");
 576 
 577             // Note that the wildcard API is written to accommodate
 578             // multiple bounds for wildcards, but at the time of
 579             // writing only a single bound is allowed in the
 580             // language.
 581             AnnotatedType[] bounds = getAnnotatedLowerBounds();
 582             if (bounds.length > 0) {
 583                 sb.append(" super ");
 584             } else {
 585                 bounds = getAnnotatedUpperBounds();
 586                 if (bounds.length > 0) {
 587                     if (bounds.length == 1) {
 588                         // Check for and elide " extends java.lang.Object" if a lone
 589                         // Object bound is not annotated.
 590                         AnnotatedType bound = bounds[0];
 591                         if (bound.getType().equals(Object.class) &&
 592                             bound.getAnnotations().length == 0) {
 593                             return sb.toString();
 594                         }
 595                     }
 596                     sb.append(" extends ");
 597                 }
 598             }
 599 
 600             sb.append(Stream.of(bounds).map(AnnotatedType::toString).
 601                       collect(Collectors.joining(" & ")));
 602 
 603             return sb.toString();
 604         }
 605 
 606 
 607         @Override
 608         public boolean equals(Object o) {
 609             if (o instanceof AnnotatedWildcardType) {
 610                 AnnotatedWildcardType that = (AnnotatedWildcardType) o;
 611                 return equalsTypeAndAnnotations(that) &&
 612                     // Treats ordering as significant
 613                     Arrays.equals(getAnnotatedLowerBounds(), that.getAnnotatedLowerBounds()) &&
 614                     // Treats ordering as significant
 615                     Arrays.equals(getAnnotatedUpperBounds(), that.getAnnotatedUpperBounds());
 616             } else {
 617                 return false;
 618             }
 619         }
 620 
 621         @Override
 622         public int hashCode() {
 623             return baseHashCode() ^
 624                 Objects.hash((Object[])getAnnotatedLowerBounds()) ^
 625                 Objects.hash((Object[])getAnnotatedUpperBounds());
 626         }
 627     }
 628 }