1 /*
   2  * Copyright (c) 2013, 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 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             return addNesting(clz.getEnclosingClass(), addTo.pushInner());
  99         } else if (type instanceof ParameterizedType) {
 100             ParameterizedType t = (ParameterizedType)type;
 101             if (t.getOwnerType() == null)
 102                 return addTo;
 103             return addNesting(t.getOwnerType(), addTo.pushInner());
 104         }
 105         return addTo;
 106     }
 107 
 108     private static boolean isArray(Type t) {
 109         if (t instanceof Class) {
 110             Class<?> c = (Class)t;
 111             if (c.isArray())
 112                 return true;
 113         } else if (t instanceof GenericArrayType) {
 114             return true;
 115         }
 116         return false;
 117     }
 118 
 119     static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
 120                                                             new TypeAnnotation[0], new TypeAnnotation[0], null);
 121 
 122     private static class AnnotatedTypeBaseImpl implements AnnotatedType {
 123         private final Type type;
 124         private final AnnotatedElement decl;
 125         private final LocationInfo location;
 126         private final TypeAnnotation[] allOnSameTargetTypeAnnotations;
 127         private final Map<Class <? extends Annotation>, Annotation> annotations;
 128 
 129         AnnotatedTypeBaseImpl(Type type, LocationInfo location,
 130                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 131                 AnnotatedElement decl) {
 132             this.type = type;
 133             this.decl = decl;
 134             this.location = location;
 135             this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
 136             this.annotations = TypeAnnotationParser.mapTypeAnnotations(location.filter(actualTypeAnnotations));
 137         }
 138 
 139         // AnnotatedElement
 140         @Override
 141         public final Annotation[] getAnnotations() {
 142             return getDeclaredAnnotations();
 143         }
 144 
 145         @Override
 146         public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
 147             return getDeclaredAnnotation(annotation);
 148         }
 149 
 150         @Override
 151         public final <T extends Annotation> T[] getAnnotations(Class<T> annotation) {
 152             return getDeclaredAnnotations(annotation);
 153         }
 154 
 155         @Override
 156         public Annotation[] getDeclaredAnnotations() {
 157             return annotations.values().toArray(new Annotation[0]);
 158         }
 159 
 160         @Override
 161         @SuppressWarnings("unchecked")
 162         public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
 163             return (T)annotations.get(annotation);
 164         }
 165 
 166         @Override
 167         public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotation) {
 168             return AnnotationSupport.getMultipleAnnotations(annotations, annotation);
 169         }
 170 
 171         // AnnotatedType
 172         @Override
 173         public Type getType() {
 174             return type;
 175         }
 176 
 177         // Implementation details
 178         LocationInfo getLocation() {
 179             return location;
 180         }
 181         TypeAnnotation[] getTypeAnnotations() {
 182             return allOnSameTargetTypeAnnotations;
 183         }
 184         AnnotatedElement getDecl() {
 185             return decl;
 186         }
 187     }
 188 
 189     private static class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
 190         AnnotatedArrayTypeImpl(Type type, LocationInfo location,
 191                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 192                 AnnotatedElement decl) {
 193             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 194         }
 195 
 196         @Override
 197         public AnnotatedType getAnnotatedGenericComponentType() {
 198             return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
 199                                                            getLocation().pushArray(),
 200                                                            getTypeAnnotations(),
 201                                                            getTypeAnnotations(),
 202                                                            getDecl());
 203         }
 204 
 205         private Type getComponentType() {
 206             Type t = getType();
 207             if (t instanceof Class) {
 208                 Class<?> c = (Class)t;
 209                 return c.getComponentType();
 210             }
 211             return ((GenericArrayType)t).getGenericComponentType();
 212         }
 213     }
 214 
 215     private static class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
 216         AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
 217                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 218                 AnnotatedElement decl) {
 219             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 220         }
 221 
 222         @Override
 223         public AnnotatedType[] getAnnotatedBounds() {
 224             return getTypeVariable().getAnnotatedBounds();
 225         }
 226 
 227         private TypeVariable<?> getTypeVariable() {
 228             return (TypeVariable)getType();
 229         }
 230     }
 231 
 232     private static class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedParameterizedType {
 233         AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
 234                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 235                 AnnotatedElement decl) {
 236             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 237         }
 238 
 239         @Override
 240         public AnnotatedType[] getAnnotatedActualTypeArguments() {
 241             Type[] arguments = getParameterizedType().getActualTypeArguments();
 242             AnnotatedType[] res = new AnnotatedType[arguments.length];
 243             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 244             int initialCapacity = getTypeAnnotations().length;
 245             for (int i = 0; i < res.length; i++) {
 246                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 247                 LocationInfo newLoc = getLocation().pushTypeArg((byte)i);
 248                 for (TypeAnnotation t : getTypeAnnotations())
 249                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 250                         l.add(t);
 251                 res[i] = buildAnnotatedType(arguments[i],
 252                                             newLoc,
 253                                             l.toArray(new TypeAnnotation[0]),
 254                                             getTypeAnnotations(),
 255                                             getDecl());
 256             }
 257             return res;
 258         }
 259 
 260         private ParameterizedType getParameterizedType() {
 261             return (ParameterizedType)getType();
 262         }
 263     }
 264 
 265     private static class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
 266         private final boolean hasUpperBounds;
 267         AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
 268                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 269                 AnnotatedElement decl) {
 270             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 271             hasUpperBounds = (type.getLowerBounds().length == 0);
 272         }
 273 
 274         @Override
 275         public AnnotatedType[] getAnnotatedUpperBounds() {
 276             if (!hasUpperBounds())
 277                 return new AnnotatedType[0];
 278             return getAnnotatedBounds(getWildcardType().getUpperBounds());
 279         }
 280 
 281         @Override
 282         public AnnotatedType[] getAnnotatedLowerBounds() {
 283             if (hasUpperBounds)
 284                 return new AnnotatedType[0];
 285             return getAnnotatedBounds(getWildcardType().getLowerBounds());
 286         }
 287 
 288         private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
 289             AnnotatedType[] res = new AnnotatedType[bounds.length];
 290             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 291             LocationInfo newLoc = getLocation().pushWildcard();
 292             int initialCapacity = getTypeAnnotations().length;
 293             for (int i = 0; i < res.length; i++) {
 294                 List<TypeAnnotation> l = new ArrayList<>(initialCapacity);
 295                 for (TypeAnnotation t : getTypeAnnotations())
 296                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 297                         l.add(t);
 298                 res[i] = buildAnnotatedType(bounds[i],
 299                                             newLoc,
 300                                             l.toArray(new TypeAnnotation[0]),
 301                                             getTypeAnnotations(),
 302                                             getDecl());
 303             }
 304             return res;
 305         }
 306 
 307         private WildcardType getWildcardType() {
 308             return (WildcardType)getType();
 309         }
 310 
 311         private boolean hasUpperBounds() {
 312             return hasUpperBounds;
 313         }
 314     }
 315 }