1 /*
   2  * Copyright (c) 2013, 2015, 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
 208         public String toString() {
 209             Annotation[] annotations = getAnnotations();
 210             StringJoiner sj = new StringJoiner("\n");
 211             if (annotations != null) {
 212                 for (Annotation annotation : annotations) {
 213                     sj.add(annotation.toString());
 214                 }
 215                 sj.add(""); // Add a newline
 216             }
 217             return sj.toString() + type.toString();
 218         }
 219 
 220         /*
 221          * Testing notes: see if type.toString() is a postfix of AnnotatedType.toString()
 222 
 223          * For the annotations, for multiple annotations, compare with
 224          * a runtime construction since the order of annotations from
 225          * getAnnotations is not specified.
 226          */
 227 
 228         boolean equalsTypeAndAnnotations(AnnotatedType that) {
 229             return getType().equals(that.getType()) &&
 230                 // Treat ordering of annotations as significant
 231                 Arrays.equals(getAnnotations(), that.getAnnotations()) &&
 232                 Objects.equals(getAnnotatedOwnerType(), that.getAnnotatedOwnerType());
 233         }
 234 
 235         int baseHashCode() {
 236             return type.hashCode() ^
 237                 // Acceptable to use Objects.hash rather than
 238                 // Arrays.deepHashCode since the elements of the array
 239                 // are not themselves arrays.
 240                 Objects.hash((Object[])getAnnotations());
 241         }
 242 
 243         // Implementation details
 244         final LocationInfo getLocation() {
 245             return location;
 246         }
 247         final TypeAnnotation[] getTypeAnnotations() {
 248             return allOnSameTargetTypeAnnotations;
 249         }
 250         final AnnotatedElement getDecl() {
 251             return decl;
 252         }
 253     }
 254 
 255     private static final class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
 256         AnnotatedArrayTypeImpl(Type type, LocationInfo location,
 257                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 258                 AnnotatedElement decl) {
 259             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 260         }
 261 
 262         @Override
 263         public AnnotatedType getAnnotatedGenericComponentType() {
 264             Type t = getComponentType();
 265             return AnnotatedTypeFactory.buildAnnotatedType(t,
 266                     nestingForType(t, getLocation().pushArray()),
 267                     getTypeAnnotations(),
 268                     getTypeAnnotations(),
 269                     getDecl());
 270         }
 271 
 272         @Override
 273         public AnnotatedType getAnnotatedOwnerType() {
 274             return null;
 275         }
 276 
 277         private Type getComponentType() {
 278             Type t = getType();
 279             if (t instanceof Class) {
 280                 Class<?> c = (Class)t;
 281                 return c.getComponentType();
 282             }
 283             return ((GenericArrayType)t).getGenericComponentType();
 284         }
 285 
 286         @Override
 287         public boolean equals(Object o) {
 288             if (o instanceof AnnotatedArrayType) {
 289                 AnnotatedArrayType that = (AnnotatedArrayType) o;
 290                 return equalsTypeAndAnnotations(that) &&
 291                     Objects.equals(getAnnotatedGenericComponentType(),
 292                                    that.getAnnotatedGenericComponentType());
 293             } else {
 294                 return false;
 295             }
 296         }
 297 
 298         @Override
 299         public int hashCode() {
 300             return baseHashCode() ^ getAnnotatedGenericComponentType().hashCode();
 301         }
 302     }
 303 
 304     private static final class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
 305         AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
 306                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 307                 AnnotatedElement decl) {
 308             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 309         }
 310 
 311         @Override
 312         public AnnotatedType[] getAnnotatedBounds() {
 313             return getTypeVariable().getAnnotatedBounds();
 314         }
 315 
 316         @Override
 317         public AnnotatedType getAnnotatedOwnerType() {
 318             return null;
 319         }
 320 
 321         private TypeVariable<?> getTypeVariable() {
 322             return (TypeVariable)getType();
 323         }
 324 
 325         @Override
 326         public boolean equals(Object o) {
 327             if (o instanceof AnnotatedTypeVariable) {
 328                 AnnotatedTypeVariable that = (AnnotatedTypeVariable) o;
 329                 return equalsTypeAndAnnotations(that) &&
 330                     Arrays.equals(getAnnotatedBounds(), that.getAnnotatedBounds());
 331             } else {
 332                 return false;
 333             }
 334         }
 335 
 336         @Override
 337         public int hashCode() {
 338             return baseHashCode() ^
 339                 Objects.hash((Object[])getAnnotatedBounds());
 340         }
 341     }
 342 
 343     private static final class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl
 344             implements AnnotatedParameterizedType {
 345         AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
 346                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 347                 AnnotatedElement decl) {
 348             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 349         }
 350 
 351         @Override
 352         public AnnotatedType[] getAnnotatedActualTypeArguments() {
 353             Type[] arguments = getParameterizedType().getActualTypeArguments();
 354             AnnotatedType[] res = new AnnotatedType[arguments.length];
 355             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 356             int initialCapacity = getTypeAnnotations().length;
 357             for (int i = 0; i < res.length; i++) {
 358                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 359                 LocationInfo newLoc = nestingForType(arguments[i], getLocation().pushTypeArg((byte)i));
 360                 for (TypeAnnotation t : getTypeAnnotations())
 361                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 362                         l.add(t);
 363                 res[i] = buildAnnotatedType(arguments[i],
 364                         newLoc,
 365                         l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
 366                         getTypeAnnotations(),
 367                         getDecl());
 368             }
 369             return res;
 370         }
 371 
 372         @Override
 373         public AnnotatedType getAnnotatedOwnerType() {
 374             Type owner = getParameterizedType().getOwnerType();
 375             if (owner == null)
 376                 return null;
 377             LocationInfo outerLoc = nestingForType(owner, getLocation().popAllLocations((byte)1));
 378             TypeAnnotation[]all = getTypeAnnotations();
 379             List<TypeAnnotation> l = new ArrayList<>(all.length);
 380 
 381             for (TypeAnnotation t : all)
 382                 if (t.getLocationInfo().isSameLocationInfo(outerLoc))
 383                     l.add(t);
 384 
 385             return buildAnnotatedType(owner, outerLoc, l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY), all, getDecl());
 386         }
 387 
 388         private ParameterizedType getParameterizedType() {
 389             return (ParameterizedType)getType();
 390         }
 391 
 392         @Override
 393         public boolean equals(Object o) {
 394             if (o instanceof AnnotatedParameterizedType) {
 395                 AnnotatedParameterizedType that = (AnnotatedParameterizedType) o;
 396                 return equalsTypeAndAnnotations(that) &&
 397                     Arrays.equals(getAnnotatedActualTypeArguments(), that.getAnnotatedActualTypeArguments());
 398             } else {
 399                 return false;
 400             }
 401         }
 402 
 403         @Override
 404         public int hashCode() {
 405             return baseHashCode() ^
 406                 Objects.hash((Object[])getAnnotatedActualTypeArguments());
 407         }
 408     }
 409 
 410     private static final class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
 411         private final boolean hasUpperBounds;
 412         AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
 413                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 414                 AnnotatedElement decl) {
 415             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 416             hasUpperBounds = (type.getLowerBounds().length == 0);
 417         }
 418 
 419         @Override
 420         public AnnotatedType[] getAnnotatedUpperBounds() {
 421             if (!hasUpperBounds()) {
 422                 return new AnnotatedType[] { buildAnnotatedType(Object.class,
 423                         LocationInfo.BASE_LOCATION,
 424                         EMPTY_TYPE_ANNOTATION_ARRAY,
 425                         EMPTY_TYPE_ANNOTATION_ARRAY,
 426                         null)
 427                 };
 428             }
 429             return getAnnotatedBounds(getWildcardType().getUpperBounds());
 430         }
 431 
 432         @Override
 433         public AnnotatedType[] getAnnotatedLowerBounds() {
 434             if (hasUpperBounds)
 435                 return new AnnotatedType[0];
 436             return getAnnotatedBounds(getWildcardType().getLowerBounds());
 437         }
 438 
 439         @Override
 440         public AnnotatedType getAnnotatedOwnerType() {
 441             return null;
 442         }
 443 
 444         private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
 445             AnnotatedType[] res = new AnnotatedType[bounds.length];
 446             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 447             int initialCapacity = getTypeAnnotations().length;
 448             for (int i = 0; i < res.length; i++) {
 449                 LocationInfo newLoc = nestingForType(bounds[i], getLocation().pushWildcard());
 450                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 451                 for (TypeAnnotation t : getTypeAnnotations())
 452                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 453                         l.add(t);
 454                 res[i] = buildAnnotatedType(bounds[i],
 455                         newLoc,
 456                         l.toArray(EMPTY_TYPE_ANNOTATION_ARRAY),
 457                         getTypeAnnotations(),
 458                         getDecl());
 459             }
 460             return res;
 461         }
 462 
 463         private WildcardType getWildcardType() {
 464             return (WildcardType)getType();
 465         }
 466 
 467         private boolean hasUpperBounds() {
 468             return hasUpperBounds;
 469         }
 470 
 471         @Override
 472         public boolean equals(Object o) {
 473             if (o instanceof AnnotatedWildcardType) {
 474                 AnnotatedWildcardType that = (AnnotatedWildcardType) o;
 475                 return equalsTypeAndAnnotations(that) &&
 476                     // Treats ordering as significant
 477                     Arrays.equals(getAnnotatedLowerBounds(), that.getAnnotatedLowerBounds()) &&
 478                     // Treats ordering as significant
 479                     Arrays.equals(getAnnotatedUpperBounds(), that.getAnnotatedUpperBounds());
 480             } else {
 481                 return false;
 482             }
 483         }
 484 
 485         @Override
 486         public int hashCode() {
 487             return baseHashCode() ^
 488                 Objects.hash((Object[])getAnnotatedLowerBounds()) ^
 489                 Objects.hash((Object[])getAnnotatedUpperBounds());
 490         }
 491     }
 492 }