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 
  35 import static sun.reflect.annotation.TypeAnnotation.*;
  36 
  37 public final class AnnotatedTypeFactory {
  38     /**
  39      * Create an AnnotatedType.
  40      *
  41      * @param type the type this AnnotatedType corresponds to
  42      * @param currentLoc the location this AnnotatedType corresponds to
  43      * @param actualTypeAnnos the type annotations this AnnotatedType has
  44      * @param allOnSameTarget all type annotation on the same TypeAnnotationTarget
  45      *                          as the AnnotatedType being built
  46      * @param decl the declaration having the type use this AnnotatedType
  47      *                          corresponds to
  48      */
  49     public static AnnotatedType buildAnnotatedType(Type type,
  50             LocationInfo currentLoc,
  51             TypeAnnotation[] actualTypeAnnos,
  52             TypeAnnotation[] allOnSameTarget,
  53             AnnotatedElement decl) {
  54         if (type == null) {
  55             return EMPTY_ANNOTATED_TYPE;
  56         }
  57         if (isArray(type))
  58             return new AnnotatedArrayTypeImpl(type,
  59                     currentLoc,
  60                     actualTypeAnnos,
  61                     allOnSameTarget,
  62                     decl);
  63         if (type instanceof Class) {
  64             return new AnnotatedTypeBaseImpl(type,
  65                     addNesting(type, currentLoc),
  66                     actualTypeAnnos,
  67                     allOnSameTarget,
  68                     decl);
  69         } else if (type instanceof TypeVariable) {
  70             return new AnnotatedTypeVariableImpl((TypeVariable)type,
  71                     currentLoc,
  72                     actualTypeAnnos,
  73                     allOnSameTarget,
  74                     decl);
  75         } else if (type instanceof ParameterizedType) {
  76             return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
  77                     addNesting(type, currentLoc),
  78                     actualTypeAnnos,
  79                     allOnSameTarget,
  80                     decl);
  81         } else if (type instanceof WildcardType) {
  82             return new AnnotatedWildcardTypeImpl((WildcardType) type,
  83                     currentLoc,
  84                     actualTypeAnnos,
  85                     allOnSameTarget,
  86                     decl);
  87         }
  88         throw new AssertionError("Unknown instance of Type: " + type + "\nThis should not happen.");
  89     }
  90 
  91     private static LocationInfo addNesting(Type type, LocationInfo addTo) {
  92         if (isArray(type))
  93             return addTo;
  94         if (type instanceof Class) {
  95             Class<?> clz = (Class)type;
  96             if (clz.getEnclosingClass() == null)
  97                 return addTo;
  98             if (Modifier.isStatic(clz.getModifiers()))
  99                 return addNesting(clz.getEnclosingClass(), addTo);
 100             return addNesting(clz.getEnclosingClass(), addTo.pushInner());
 101         } else if (type instanceof ParameterizedType) {
 102             ParameterizedType t = (ParameterizedType)type;
 103             if (t.getOwnerType() == null)
 104                 return addTo;
 105             return addNesting(t.getOwnerType(), addTo.pushInner());
 106         }
 107         return addTo;
 108     }
 109 
 110     private static boolean isArray(Type t) {
 111         if (t instanceof Class) {
 112             Class<?> c = (Class)t;
 113             if (c.isArray())
 114                 return true;
 115         } else if (t instanceof GenericArrayType) {
 116             return true;
 117         }
 118         return false;
 119     }
 120 
 121     static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
 122                                                             new TypeAnnotation[0], new TypeAnnotation[0], null);
 123     static final AnnotatedType[] EMPTY_ANNOTATED_TYPE_ARRAY = new AnnotatedType[0];
 124 
 125     private static class AnnotatedTypeBaseImpl implements AnnotatedType {
 126         private final Type type;
 127         private final AnnotatedElement decl;
 128         private final LocationInfo location;
 129         private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
 130         private final Map<Class <? extends Annotation>, Annotation> annotations;
 131 
 132         AnnotatedTypeBaseImpl(Type type, LocationInfo location,
 133                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 134                 AnnotatedElement decl) {
 135             this.type = type;
 136             this.decl = decl;
 137             this.location = location;
 138             this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
 139             this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations));
 140         }
 141 
 142         // AnnotatedElement
 143         @Override
 144         public final Annotation[] getAnnotations() {
 145             return getDeclaredAnnotations();
 146         }
 147 
 148         @Override
 149         public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
 150             return getDeclaredAnnotation(annotation);
 151         }
 152 
 153         @Override
 154         public final <T extends Annotation> T[] getAnnotationsByType(Class<T> annotation) {
 155             return getDeclaredAnnotationsByType(annotation);
 156         }
 157 
 158         @Override
 159         public final Annotation[] getDeclaredAnnotations() {
 160             return annotations.values().toArray(new Annotation[0]);
 161         }
 162 
 163         @Override
 164         @SuppressWarnings("unchecked")
 165         public final <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
 166             return (T)annotations.get(annotation);
 167         }
 168 
 169         @Override
 170         public final <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotation) {
 171             return AnnotationSupport.getDirectlyAndIndirectlyPresent(annotations, annotation);
 172         }
 173 
 174         // AnnotatedType
 175         @Override
 176         public final Type getType() {
 177             return type;
 178         }
 179 
 180         // Implementation details
 181         final LocationInfo getLocation() {
 182             return location;
 183         }
 184         final TypeAnnotation[] getTypeAnnotations() {
 185             return allOnSameTargetTypeAnnotations;
 186         }
 187         final AnnotatedElement getDecl() {
 188             return decl;
 189         }
 190     }
 191 
 192     private static final class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
 193         AnnotatedArrayTypeImpl(Type type, LocationInfo location,
 194                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 195                 AnnotatedElement decl) {
 196             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 197         }
 198 
 199         @Override
 200         public AnnotatedType getAnnotatedGenericComponentType() {
 201             return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
 202                                                            getLocation().pushArray(),
 203                                                            getTypeAnnotations(),
 204                                                            getTypeAnnotations(),
 205                                                            getDecl());
 206         }
 207 
 208         private Type getComponentType() {
 209             Type t = getType();
 210             if (t instanceof Class) {
 211                 Class<?> c = (Class)t;
 212                 return c.getComponentType();
 213             }
 214             return ((GenericArrayType)t).getGenericComponentType();
 215         }
 216     }
 217 
 218     private static final class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
 219         AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
 220                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 221                 AnnotatedElement decl) {
 222             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 223         }
 224 
 225         @Override
 226         public AnnotatedType[] getAnnotatedBounds() {
 227             return getTypeVariable().getAnnotatedBounds();
 228         }
 229 
 230         private TypeVariable<?> getTypeVariable() {
 231             return (TypeVariable)getType();
 232         }
 233     }
 234 
 235     private static final class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl
 236             implements AnnotatedParameterizedType {
 237         AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
 238                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 239                 AnnotatedElement decl) {
 240             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 241         }
 242 
 243         @Override
 244         public AnnotatedType[] getAnnotatedActualTypeArguments() {
 245             Type[] arguments = getParameterizedType().getActualTypeArguments();
 246             AnnotatedType[] res = new AnnotatedType[arguments.length];
 247             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 248             int initialCapacity = getTypeAnnotations().length;
 249             for (int i = 0; i < res.length; i++) {
 250                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 251                 LocationInfo newLoc = getLocation().pushTypeArg((byte)i);
 252                 for (TypeAnnotation t : getTypeAnnotations())
 253                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 254                         l.add(t);
 255                 res[i] = buildAnnotatedType(arguments[i],
 256                                             newLoc,
 257                                             l.toArray(new TypeAnnotation[0]),
 258                                             getTypeAnnotations(),
 259                                             getDecl());
 260             }
 261             return res;
 262         }
 263 
 264         private ParameterizedType getParameterizedType() {
 265             return (ParameterizedType)getType();
 266         }
 267     }
 268 
 269     private static final class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
 270         private final boolean hasUpperBounds;
 271         AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
 272                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 273                 AnnotatedElement decl) {
 274             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 275             hasUpperBounds = (type.getLowerBounds().length == 0);
 276         }
 277 
 278         @Override
 279         public AnnotatedType[] getAnnotatedUpperBounds() {
 280             if (!hasUpperBounds()) {
 281                 return new AnnotatedType[] { buildAnnotatedType(Object.class,
 282                                                                 LocationInfo.BASE_LOCATION,
 283                                                                 new TypeAnnotation[0],
 284                                                                 new TypeAnnotation[0],
 285                                                                 null)
 286                                            };
 287             }
 288             return getAnnotatedBounds(getWildcardType().getUpperBounds());
 289         }
 290 
 291         @Override
 292         public AnnotatedType[] getAnnotatedLowerBounds() {
 293             if (hasUpperBounds)
 294                 return new AnnotatedType[0];
 295             return getAnnotatedBounds(getWildcardType().getLowerBounds());
 296         }
 297 
 298         private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
 299             AnnotatedType[] res = new AnnotatedType[bounds.length];
 300             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 301             LocationInfo newLoc = getLocation().pushWildcard();
 302             int initialCapacity = getTypeAnnotations().length;
 303             for (int i = 0; i < res.length; i++) {
 304                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 305                 for (TypeAnnotation t : getTypeAnnotations())
 306                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 307                         l.add(t);
 308                 res[i] = buildAnnotatedType(bounds[i],
 309                                             newLoc,
 310                                             l.toArray(new TypeAnnotation[0]),
 311                                             getTypeAnnotations(),
 312                                             getDecl());
 313             }
 314             return res;
 315         }
 316 
 317         private WildcardType getWildcardType() {
 318             return (WildcardType)getType();
 319         }
 320 
 321         private boolean hasUpperBounds() {
 322             return hasUpperBounds;
 323         }
 324     }
 325 }