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     public static AnnotatedType buildAnnotatedType(Type type,
  39                                                    LocationInfo currentLoc,
  40                                                    TypeAnnotation[] actualTypeAnnos,
  41                                                    TypeAnnotation[] allOnSameTarget,
  42                                                    AnnotatedElement decl) {
  43         if (type == null) {
  44             return EMPTY_ANNOTATED_TYPE;
  45         }
  46         if (isArray(type))
  47             return new AnnotatedArrayTypeImpl(type,
  48                     currentLoc,
  49                     actualTypeAnnos,
  50                     allOnSameTarget,
  51                     decl);
  52         if (type instanceof Class) {
  53             return new AnnotatedTypeBaseImpl(type,
  54                     addNesting(type, currentLoc),
  55                     actualTypeAnnos,
  56                     allOnSameTarget,
  57                     decl);
  58         } else if (type instanceof TypeVariable) {
  59             return new AnnotatedTypeVariableImpl((TypeVariable)type,
  60                     currentLoc,
  61                     actualTypeAnnos,
  62                     allOnSameTarget,
  63                     decl);
  64         } else if (type instanceof ParameterizedType) {
  65             return new AnnotatedParameterizedTypeImpl((ParameterizedType)type,
  66                     addNesting(type, currentLoc),
  67                     actualTypeAnnos,
  68                     allOnSameTarget,
  69                     decl);
  70         } else if (type instanceof WildcardType) {
  71             return new AnnotatedWildcardTypeImpl((WildcardType) type,
  72                     currentLoc,
  73                     actualTypeAnnos,
  74                     allOnSameTarget,
  75                     decl);
  76         }
  77         // Assert here? because this should not be happening
  78         return EMPTY_ANNOTATED_TYPE;
  79     }
  80 
  81     private static LocationInfo addNesting(Type type, LocationInfo addTo) {
  82         if (isArray(type))
  83             return addTo;
  84         if (type instanceof Class) {
  85             Class<?> clz = (Class)type;
  86             if (clz.getEnclosingClass() == null)
  87                 return addTo;
  88             return addNesting(clz.getEnclosingClass(), addTo.pushInner());
  89         } else if (type instanceof ParameterizedType) {
  90             ParameterizedType t = (ParameterizedType)type;
  91             if (t.getOwnerType() == null)
  92                 return addTo;
  93             return addNesting(t.getOwnerType(), addTo.pushInner());
  94         }
  95         return addTo;
  96     }
  97 
  98     private static boolean isArray(Type t) {
  99         if (t instanceof Class) {
 100             Class<?> c = (Class)t;
 101             if (c.isArray())
 102                 return true;
 103         } else if (t instanceof GenericArrayType) {
 104             return true;
 105         }
 106         return false;
 107     }
 108 
 109     static final AnnotatedType EMPTY_ANNOTATED_TYPE = new AnnotatedTypeBaseImpl(null, LocationInfo.BASE_LOCATION,
 110                                                             new TypeAnnotation[0], new TypeAnnotation[0], null);
 111 
 112     private static class AnnotatedTypeBaseImpl implements AnnotatedType {
 113         private Type type;
 114         private AnnotatedElement decl;
 115         private LocationInfo location;
 116         private TypeAnnotation[] allOnSameTargetTypeAnnotations;
 117         private Map<Class <? extends Annotation>, Annotation> annotations;
 118 
 119         AnnotatedTypeBaseImpl(Type type, LocationInfo location,
 120                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 121                 AnnotatedElement decl) {
 122             this.type = type;
 123             this.decl = decl;
 124             this.location = location;
 125             this.allOnSameTargetTypeAnnotations = allOnSameTargetTypeAnnotations;
 126             this.annotations = TypeAnnotationParser.mapAnnotations(location.filter(actualTypeAnnotations));
 127         }
 128         public final boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
 129             return annotations.get(annotation) != null;
 130         }
 131         public final Annotation[] getAnnotations() {
 132             return getDeclaredAnnotations();
 133         }
 134         public final <T extends Annotation> T getAnnotation(Class<T> annotation) {
 135             return getDeclaredAnnotation(annotation);
 136         }
 137         public final <T extends Annotation> T[] getAnnotations(Class<T> annotation) {
 138             return getDeclaredAnnotations(annotation);
 139         }
 140         public Annotation[] getDeclaredAnnotations() {
 141             return annotations.values().toArray(new Annotation[0]);
 142         }
 143         @SuppressWarnings("unchecked")
 144         public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotation) {
 145             return (T)annotations.get(annotation);
 146         }
 147         public <T extends Annotation> T[] getDeclaredAnnotations(Class<T> annotation) {
 148             return AnnotationSupport.getMultipleAnnotations(annotations, annotation);
 149         }
 150 
 151         Type getType() {
 152             return type;
 153         }
 154         LocationInfo getLocation() {
 155             return location;
 156         }
 157         TypeAnnotation[] getTypeAnnotations() {
 158             return allOnSameTargetTypeAnnotations;
 159         }
 160         AnnotatedElement getDecl() {
 161             return decl;
 162         }
 163     }
 164 
 165     private static class AnnotatedArrayTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedArrayType {
 166         AnnotatedArrayTypeImpl(Type type, LocationInfo location,
 167                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 168                 AnnotatedElement decl) {
 169             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 170         }
 171         public AnnotatedType getAnnotatedGenericComponentType() {
 172             return AnnotatedTypeFactory.buildAnnotatedType(getComponentType(),
 173                                                            getLocation().pushArray(),
 174                                                            getTypeAnnotations(),
 175                                                            getTypeAnnotations(),
 176                                                            getDecl());
 177         }
 178         private Type getComponentType() {
 179             Type t = getType();
 180             if (t instanceof Class) {
 181                 Class<?> c = (Class)t;
 182                 return c.getComponentType();
 183             }
 184             return ((GenericArrayType)t).getGenericComponentType();
 185         }
 186     }
 187 
 188     private static class AnnotatedTypeVariableImpl extends AnnotatedTypeBaseImpl implements AnnotatedTypeVariable {
 189         AnnotatedTypeVariableImpl(TypeVariable<?> type, LocationInfo location,
 190                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 191                 AnnotatedElement decl) {
 192             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 193         }
 194 
 195         private TypeVariable<?> getTypeVariable() {
 196             return (TypeVariable)getType();
 197         }
 198         public AnnotatedType[] getAnnotatedBounds() {
 199             return getTypeVariable().getAnnotatedBounds();
 200         }
 201     }
 202 
 203     private static class AnnotatedParameterizedTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedParameterizedType {
 204         AnnotatedParameterizedTypeImpl(ParameterizedType type, LocationInfo location,
 205                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 206                 AnnotatedElement decl) {
 207             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 208         }
 209         public AnnotatedType[] getAnnotatedActualTypeArguments() {
 210             Type[] arguments = getParameterizedType().getActualTypeArguments();
 211             AnnotatedType[] res = new AnnotatedType[arguments.length];
 212             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 213             for (int i = 0; i < res.length; i++) {
 214                 List<TypeAnnotation> l = new ArrayList<>();
 215                 LocationInfo newLoc = getLocation().pushTypeArg((byte)i);
 216                 for (TypeAnnotation t : getTypeAnnotations())
 217                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 218                         l.add(t);
 219                 res[i] = buildAnnotatedType(arguments[i],
 220                                             newLoc,
 221                                             l.toArray(new TypeAnnotation[0]),
 222                                             getTypeAnnotations(),
 223                                             getDecl());
 224             }
 225             return res;
 226         }
 227 
 228         private ParameterizedType getParameterizedType() {
 229             return (ParameterizedType)getType();
 230         }
 231     }
 232 
 233     private static class AnnotatedWildcardTypeImpl extends AnnotatedTypeBaseImpl implements AnnotatedWildcardType {
 234         private boolean hasUpperBounds;
 235         AnnotatedWildcardTypeImpl(WildcardType type, LocationInfo location,
 236                 TypeAnnotation[] actualTypeAnnotations, TypeAnnotation[] allOnSameTargetTypeAnnotations,
 237                 AnnotatedElement decl) {
 238             super(type, location, actualTypeAnnotations, allOnSameTargetTypeAnnotations, decl);
 239             hasUpperBounds = (type.getLowerBounds().length == 0);
 240         }
 241 
 242         public AnnotatedType[] getAnnotatedUpperBounds() {
 243             if (!hasUpperBounds())
 244                 return new AnnotatedType[0];
 245             return getAnnotatedBounds(getWildcardType().getUpperBounds());
 246         }
 247 
 248         public AnnotatedType[] getAnnotatedLowerBounds() {
 249             if (hasUpperBounds)
 250                 return new AnnotatedType[0];
 251             return getAnnotatedBounds(getWildcardType().getLowerBounds());
 252         }
 253 
 254         private AnnotatedType[] getAnnotatedBounds(Type[] bounds) {
 255             AnnotatedType[] res = new AnnotatedType[bounds.length];
 256             Arrays.fill(res, EMPTY_ANNOTATED_TYPE);
 257             LocationInfo newLoc = getLocation().pushWildcard();
 258             for (int i = 0; i < res.length; i++) {
 259                 List<TypeAnnotation> l = new ArrayList<>();
 260                 for (TypeAnnotation t : getTypeAnnotations())
 261                     if (t.getLocationInfo().isSameLocationInfo(newLoc))
 262                         l.add(t);
 263                 res[i] = buildAnnotatedType(bounds[i],
 264                                             newLoc,
 265                                             l.toArray(new TypeAnnotation[0]),
 266                                             getTypeAnnotations(),
 267                                             getDecl());
 268             }
 269             return res;
 270         }
 271 
 272         private WildcardType getWildcardType() {
 273             return (WildcardType)getType();
 274         }
 275 
 276         private boolean hasUpperBounds() {
 277             return hasUpperBounds;
 278         }
 279     }
 280 }