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 
  37 import static sun.reflect.annotation.TypeAnnotation.*;
  38 
  39 public final class AnnotatedTypeFactory {
  40     /**
  41      * Create an AnnotatedType.
  42      *
  43      * @param type the type this AnnotatedType corresponds to
  44      * @param currentLoc the location this AnnotatedType corresponds to
  45      * @param actualTypeAnnos the type annotations this AnnotatedType has
  46      * @param allOnSameTarget all type annotation on the same TypeAnnotationTarget
  47      *                          as the AnnotatedType being built
  48      * @param decl the declaration having the type use this AnnotatedType
  49      *                          corresponds to
  50      */
  51     public static AnnotatedType buildAnnotatedType(Type type,
  52             LocationInfo currentLoc,
  53             TypeAnnotation[] actualTypeAnnos,
  54             TypeAnnotation[] allOnSameTarget,
  55             AnnotatedElement decl) {
  56         if (type == null) {
  57             return EMPTY_ANNOTATED_TYPE;
  58         }
  59         if (isArray(type))
  60             return new AnnotatedArrayTypeImpl(type,
  61                     currentLoc,
  62                     actualTypeAnnos,
  63                     allOnSameTarget,
  64                     decl);
  65         if (type instanceof Class) {
  66             return new AnnotatedTypeBaseImpl(type,
  67                     currentLoc,
  68                     actualTypeAnnos,
  69                     allOnSameTarget,
  70                     decl);
  71         } else if (type instanceof TypeVariable) {
  72             return new AnnotatedTypeVariableImpl((TypeVariable)type,
  73                     currentLoc,
  74                     actualTypeAnnos,
  75                     allOnSameTarget,
  76                     decl);
  77         } else if (type instanceof ParameterizedType) {
  78             return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
  79                     currentLoc,
  80                     actualTypeAnnos,
  81                     allOnSameTarget,
  82                     decl);
  83         } else if (type instanceof WildcardType) {
  84             return new AnnotatedWildcardTypeImpl((WildcardType) type,
  85                     currentLoc,
  86                     actualTypeAnnos,
  87                     allOnSameTarget,
  88                     decl);
  89         }
  90         throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
  91     }
  92 
  93     public static LocationInfo nestingForType(Type type, LocationInfo addTo) {
  94         if (isArray(type))
  95             return addTo;
  96         if (type instanceof Class) {
  97             Class<?> clz = (Class)type;
  98             if (clz.getEnclosingClass() == null)
  99                 return addTo;
 100             if (Modifier.isStatic(clz.getModifiers()))
 101                 return nestingForType(clz.getEnclosingClass(), addTo);
 102             return nestingForType(clz.getEnclosingClass(), addTo.pushInner());
 103         } else if (type instanceof ParameterizedType) {
 104             ParameterizedType t = (ParameterizedType)type;
 105             if (t.getOwnerType() == null)
 106                 return addTo;
 107             return nestingForType(t.getOwnerType(), addTo.pushInner());
 108         }
 109         return addTo;
 110     }
 111 
 112     private static boolean isArray(Type t) {
 113         if (t instanceof Class) {
 114             Class<?> c = (Class)t;
 115             if (c.isArray())
 116                 return true;
 117         } else if (t instanceof GenericArrayType) {
 118             return true;
 119         }
 120         return false;
 121     }
 122 
 123     static final TypeAnnotation[] EMPTY_TYPE_ANNOTATION_ARRAY = new TypeAnnotation[0];
 124     static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
 125             EMPTY_TYPE_ANNOTATION_ARRAY, EMPTY_TYPE_ANNOTATION_ARRAY, null);
 126     static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
 127 
 128     private static class AnnotatedTypeBaseImpl implements AnnotatedType {
 129         private final Type type;
 130         private final AnnotatedElement decl;
 131         private final LocationInfo location;
 132         private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
 133         private final Map<Class <? extends Annotation>, Annotation> annotations;
 134 
 135         AnnotatedTypeBaseImpl(Type type, LocationInfo location,
 136                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 137                 AnnotatedElement decl) {
 138             this.type = type;
 139             this.decl = decl;
 140             this.location = location;
 141             this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
 142             this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations));
 143         }
 144 
 145         // AnnotatedElement
 146         @Override
 147         public final Annotation[] getAnnotations() {
 148             return getDeclaredAnnotations();
 149         }
 150 
 151         @Override
 152         public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
 153             return getDeclaredAnnotation(annotation);
 154         }
 155 
 156         @Override
 157         public final <T extends Annotation> T[] getAnnotationsByType(Class<T> annotation) {
 158             return getDeclaredAnnotationsByType(annotation);
 159         }
 160 
 161         @Override
 162         public final Annotation[] getDeclaredAnnotations() {
 163             return annotations.values().toArray(new Annotation[0]);
 164         }
 165 
 166         @Override
 167         @SuppressWarnings("unchecked")
 168         public final <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
 169             return (T)annotations.get(annotation);
 170         }
 171 
 172         @Override
 173         public final <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotation) {
 174             return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotations, annotation);
 175         }
 176 
 177         // AnnotatedType
 178         @Override
 179         public final Type getType() {
 180             return type;
 181         }
 182 
 183         @Override
 184         public AnnotatedType getAnnotatedOwnerType() {
 185             if (!(type instanceof Class<?>))
 186                 throw new IllegalStateException("Can't compute owner");
 187 
 188             Class<?> inner = (Class<?>)type;
 189             Class<?> owner = inner.getDeclaringClass();
 190             if (owner == null) // top-level, local or anonymous
 191                 return null;
 192             if (inner.isPrimitive() || inner == Void.TYPE)
 193                 return null;
 194 
 195             LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
 196             TypeAnnotation[]all = getTypeAnnotations();
 197             List<TypeAnnotation> l = new ArrayList<>(all.length);
 198 
 199             for (TypeAnnotation t : all)
 200                 if (t.getLocationInfo().isSameLocationInfo(outerLoc))
 201                     l.add(t);
 202 
 203             return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
 204 
 205         }
 206 
 207         @Override // java.lang.Object
 208         public String toString() {
 209             // Reusable toString implementation, but needs to be
 210             // specialized for quirks of arrays.
 211             return annotationsToString(getAnnotations(), false) + type.toString();
 212         }
 213 
 214         protected String annotationsToString(Annotation[] annotations, boolean leadingSpace) {
 215             if (annotations != null && annotations.length > 0) {
 216                 StringJoiner sj = new StringJoiner(" ");
 217                 if (leadingSpace) {
 218                     sj.add(""); // Add a space
 219                 }
 220 
 221                 for (Annotation annotation : annotations) {
 222                     sj.add(annotation.toString());
 223                 }
 224 
 225                 if (!leadingSpace) {
 226                     sj.add("");
 227                 }
 228                 return sj.toString();
 229             } else {
 230                 return "";
 231             }
 232         }
 233 
 234         protected boolean equalsTypeAndAnnotations(AnnotatedType that) {
 235             return getType().equals(that.getType()) &&
 236                 // Treat ordering of annotations as significant
 237                 Arrays.equals(getAnnotations(), that.getAnnotations()) &&
 238                 Objects.equals(getAnnotatedOwnerType(), that.getAnnotatedOwnerType());
 239         }
 240 
 241         int baseHashCode() {
 242             return type.hashCode() ^
 243                 // Acceptable to use Objects.hash rather than
 244                 // Arrays.deepHashCode since the elements of the array
 245                 // are not themselves arrays.
 246                 Objects.hash((Object[])getAnnotations()) ^
 247                 Objects.hash(getAnnotatedOwnerType());
 248         }
 249 
 250         @Override
 251         public boolean equals(Object o) {
 252             if (o instanceof AnnotatedType &&
 253                 !(o instanceof AnnotatedArrayType) &&
 254                 !(o instanceof AnnotatedTypeVariable) &&
 255                 !(o instanceof AnnotatedParameterizedType) &&
 256                 !(o instanceof AnnotatedWildcardType)) {
 257                 AnnotatedType that = (AnnotatedType) o;
 258                 return equalsTypeAndAnnotations(that);
 259             } else {
 260                 return false;
 261             }
 262         }
 263 
 264         @Override
 265         public int hashCode() {
 266             return baseHashCode();
 267         }
 268 
 269         // Implementation details
 270         final LocationInfo getLocation() {
 271             return location;
 272         }
 273         final TypeAnnotation[] getTypeAnnotations() {
 274             return allOnSameTargetTypeAnnotations;
 275         }
 276         final AnnotatedElement getDecl() {
 277             return decl;
 278         }
 279     }
 280 
 281     private static final class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
 282         AnnotatedArrayTypeImpl(Type type, LocationInfo location,
 283                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 284                 AnnotatedElement decl) {
 285             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 286         }
 287 
 288         @Override
 289         public AnnotatedType getAnnotatedGenericComponentType() {
 290             Type t = getComponentType();
 291             return AnnotatedTypeFactory.buildAnnotatedType(t,
 292                     nestingForType(t, getLocation().pushArray()),
 293                     getTypeAnnotations(),
 294                     getTypeAnnotations(),
 295                     getDecl());
 296         }
 297 
 298         @Override
 299         public AnnotatedType getAnnotatedOwnerType() {
 300             return null;
 301         }
 302 
 303         private Type getComponentType() {
 304             Type t = getType();
 305             if (t instanceof Class) {
 306                 Class<?> c = (Class)t;
 307                 return c.getComponentType();
 308             }
 309             return ((GenericArrayType)t).getGenericComponentType();
 310         }
 311 
 312         @Override
 313         public String toString() {
 314             // To annotate the full type of an array, the annotations
 315             // are placed between the type and the brackets. For
 316             // example, to annotate an array of Strings, the syntax used is
 317             //
 318             // String @TypeAnnotation []
 319             //
 320             // and *not*
 321             //
 322             // @TypeAnnotation String[].
 323             //
 324             // The toString output should strive to be reusable in
 325             // source code. Therefore, the general logic of putting
 326             // the annotations before a textual representation of the
 327             // type need to be overridden for arrays.
 328             StringBuilder sb = new StringBuilder();
 329 
 330             AnnotatedType componentType = this;
 331             while (componentType instanceof AnnotatedArrayType) {
 332                 AnnotatedArrayType annotatedArrayType = (AnnotatedArrayType) componentType;
 333                 sb.append(annotationsToString(annotatedArrayType.getAnnotations(), true) + "[]");
 334                 componentType = annotatedArrayType.getAnnotatedGenericComponentType();
 335             }
 336 
 337             sb.insert(0, componentType.toString());
 338             return sb.toString();
 339         }
 340 
 341         @Override
 342         public boolean equals(Object o) {
 343             if (o instanceof AnnotatedArrayType) {
 344                 AnnotatedArrayType that = (AnnotatedArrayType) o;
 345                 return equalsTypeAndAnnotations(that) &&
 346                     Objects.equals(getAnnotatedGenericComponentType(),
 347                                    that.getAnnotatedGenericComponentType());
 348             } else {
 349                 return false;
 350             }
 351         }
 352 
 353         @Override
 354         public int hashCode() {
 355             return baseHashCode() ^ getAnnotatedGenericComponentType().hashCode();
 356         }
 357     }
 358 
 359     private static final class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
 360         AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
 361                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 362                 AnnotatedElement decl) {
 363             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 364         }
 365 
 366         @Override
 367         public AnnotatedType[] getAnnotatedBounds() {
 368             return getTypeVariable().getAnnotatedBounds();
 369         }
 370 
 371         @Override
 372         public AnnotatedType getAnnotatedOwnerType() {
 373             return null;
 374         }
 375 
 376         private TypeVariable<?> getTypeVariable() {
 377             return (TypeVariable)getType();
 378         }
 379 
 380         @Override
 381         public boolean equals(Object o) {
 382             if (o instanceof AnnotatedTypeVariable) {
 383                 AnnotatedTypeVariable that = (AnnotatedTypeVariable) o;
 384                 return equalsTypeAndAnnotations(that) &&
 385                     Arrays.equals(getAnnotatedBounds(), that.getAnnotatedBounds());
 386             } else {
 387                 return false;
 388             }
 389         }
 390 
 391         @Override
 392         public int hashCode() {
 393             return baseHashCode() ^
 394                 Objects.hash((Object[])getAnnotatedBounds());
 395         }
 396     }
 397 
 398     private static final class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl
 399             implements AnnotatedParameterizedType {
 400         AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
 401                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 402                 AnnotatedElement decl) {
 403             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 404         }
 405 
 406         @Override
 407         public AnnotatedType[] getAnnotatedActualTypeArguments() {
 408             Type[] arguments = getParameterizedType().getActualTypeArguments();
 409             AnnotatedType[] res = new AnnotatedType[arguments.length];
 410             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 411             int initialCapacity = getTypeAnnotations().length;
 412             for (int i = 0; i < res.length; i++) {
 413                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 414                 LocationInfo newLoc = nestingForType(arguments[i], getLocation().pushTypeArg((byte)i));
 415                 for (TypeAnnotation t : getTypeAnnotations())
 416                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 417                         l.add(t);
 418                 res[i] = buildAnnotatedType(arguments[i],
 419                         newLoc,
 420                         l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
 421                         getTypeAnnotations(),
 422                         getDecl());
 423             }
 424             return res;
 425         }
 426 
 427         @Override
 428         public AnnotatedType getAnnotatedOwnerType() {
 429             Type owner = getParameterizedType().getOwnerType();
 430             if (owner == null)
 431                 return null;
 432             LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
 433             TypeAnnotation[]all = getTypeAnnotations();
 434             List<TypeAnnotation> l = new ArrayList<>(all.length);
 435 
 436             for (TypeAnnotation t : all)
 437                 if (t.getLocationInfo().isSameLocationInfo(outerLoc))
 438                     l.add(t);
 439 
 440             return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
 441         }
 442 
 443         private ParameterizedType getParameterizedType() {
 444             return (ParameterizedType)getType();
 445         }
 446 
 447         @Override
 448         public boolean equals(Object o) {
 449             if (o instanceof AnnotatedParameterizedType) {
 450                 AnnotatedParameterizedType that = (AnnotatedParameterizedType) o;
 451                 return equalsTypeAndAnnotations(that) &&
 452                     Arrays.equals(getAnnotatedActualTypeArguments(), that.getAnnotatedActualTypeArguments());
 453             } else {
 454                 return false;
 455             }
 456         }
 457 
 458         @Override
 459         public int hashCode() {
 460             return baseHashCode() ^
 461                 Objects.hash((Object[])getAnnotatedActualTypeArguments());
 462         }
 463     }
 464 
 465     private static final class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
 466         private final boolean hasUpperBounds;
 467         AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
 468                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 469                 AnnotatedElement decl) {
 470             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 471             hasUpperBounds = (type.getLowerBounds().length == 0);
 472         }
 473 
 474         @Override
 475         public AnnotatedType[] getAnnotatedUpperBounds() {
 476             if (!hasUpperBounds()) {
 477                 return new AnnotatedType[] { buildAnnotatedType(Object.class,
 478                         LocationInfo.BASE_LOCATION,
 479                         EMPTY_TYPE_ANNOTATION_ARRAY,
 480                         EMPTY_TYPE_ANNOTATION_ARRAY,
 481                         null)
 482                 };
 483             }
 484             return getAnnotatedBounds(getWildcardType().getUpperBounds());
 485         }
 486 
 487         @Override
 488         public AnnotatedType[] getAnnotatedLowerBounds() {
 489             if (hasUpperBounds)
 490                 return new AnnotatedType[0];
 491             return getAnnotatedBounds(getWildcardType().getLowerBounds());
 492         }
 493 
 494         @Override
 495         public AnnotatedType getAnnotatedOwnerType() {
 496             return null;
 497         }
 498 
 499         private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
 500             AnnotatedType[] res = new AnnotatedType[bounds.length];
 501             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 502             int initialCapacity = getTypeAnnotations().length;
 503             for (int i = 0; i < res.length; i++) {
 504                 LocationInfo newLoc = nestingForType(bounds[i], getLocation().pushWildcard());
 505                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 506                 for (TypeAnnotation t : getTypeAnnotations())
 507                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 508                         l.add(t);
 509                 res[i] = buildAnnotatedType(bounds[i],
 510                         newLoc,
 511                         l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
 512                         getTypeAnnotations(),
 513                         getDecl());
 514             }
 515             return res;
 516         }
 517 
 518         private WildcardType getWildcardType() {
 519             return (WildcardType)getType();
 520         }
 521 
 522         private boolean hasUpperBounds() {
 523             return hasUpperBounds;
 524         }
 525 
 526         @Override
 527         public boolean equals(Object o) {
 528             if (o instanceof AnnotatedWildcardType) {
 529                 AnnotatedWildcardType that = (AnnotatedWildcardType) o;
 530                 return equalsTypeAndAnnotations(that) &&
 531                     // Treats ordering as significant
 532                     Arrays.equals(getAnnotatedLowerBounds(), that.getAnnotatedLowerBounds()) &&
 533                     // Treats ordering as significant
 534                     Arrays.equals(getAnnotatedUpperBounds(), that.getAnnotatedUpperBounds());
 535             } else {
 536                 return false;
 537             }
 538         }
 539 
 540         @Override
 541         public int hashCode() {
 542             return baseHashCode() ^
 543                 Objects.hash((Object[])getAnnotatedLowerBounds()) ^
 544                 Objects.hash((Object[])getAnnotatedUpperBounds());
 545         }
 546     }
 547 }