Home | History | Annotate | Download | only in annotations
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.java.lang.reflect.annotations;
     18 
     19 import junit.framework.TestCase;
     20 
     21 import java.lang.annotation.Annotation;
     22 import java.lang.reflect.Constructor;
     23 import java.lang.reflect.Executable;
     24 import java.lang.reflect.Method;
     25 import java.lang.reflect.Parameter;
     26 
     27 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationA;
     28 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationB;
     29 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationC;
     30 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.AnnotationD;
     31 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Container;
     32 import libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.Repeated;
     33 
     34 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.EXPECT_EMPTY;
     35 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.annotationsToTypes;
     36 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.assertAnnotationsMatch;
     37 import static libcore.java.lang.reflect.annotations.AnnotatedElementTestSupport.set;
     38 
     39 /**
     40  * Tests for {@link Executable#getParameterAnnotations()} via the {@link Constructor} and
     41  * {@link Method} classes. See {@link  for testing of the
     42  * {@link java.lang.reflect.AnnotatedElement} methods.
     43  */
     44 public class ExecutableParameterTest extends TestCase {
     45     private static class MethodClass {
     46         public void methodWithoutAnnotatedParameters(String parameter1, String parameter2) {}
     47 
     48         public void methodWithAnnotatedParameters(@AnnotationB @AnnotationD String parameter1,
     49                 @AnnotationC @AnnotationD String parameter2) {}
     50     }
     51 
     52     public void testMethodGetParameterAnnotations() throws Exception {
     53         Method methodWithoutAnnotatedParameters = MethodClass.class.getMethod(
     54                 "methodWithoutAnnotatedParameters", String.class, String.class);
     55         Annotation[][] noParameterAnnotations = getParameterAnnotations(
     56                 methodWithoutAnnotatedParameters, 2);
     57         assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
     58         assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
     59 
     60         Method methodWithAnnotatedParameters = MethodClass.class.getMethod(
     61                 "methodWithAnnotatedParameters", String.class, String.class);
     62         Annotation[][] parameterAnnotations = getParameterAnnotations(
     63                 methodWithAnnotatedParameters, 2);
     64         assertEquals(set(AnnotationB.class, AnnotationD.class),
     65                 annotationsToTypes(parameterAnnotations[0]));
     66         assertEquals(set(AnnotationC.class, AnnotationD.class),
     67                 annotationsToTypes(parameterAnnotations[1]));
     68     }
     69 
     70     private static class AnnotatedMethodClass {
     71         void noAnnotation(String p0) {}
     72 
     73         void multipleAnnotationOddity(
     74                 @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) String p0) {}
     75 
     76         void multipleAnnotationExplicitSingle(@Container({@Repeated(1)}) String p0) {}
     77 
     78         void multipleAnnotation(@Repeated(1) @Repeated(2) String p0) {}
     79 
     80         void singleAnnotation(@Repeated(1) String p0) {}
     81 
     82         static void staticSingleAnnotation(@Repeated(1) String p0) {}
     83 
     84         static Method getMethodWithoutAnnotations() throws Exception {
     85             return AnnotatedMethodClass.class.getDeclaredMethod("noAnnotation", String.class);
     86         }
     87 
     88         static Method getMethodMultipleAnnotationOddity() throws Exception {
     89             return AnnotatedMethodClass.class.getDeclaredMethod(
     90                     "multipleAnnotationOddity", String.class);
     91         }
     92 
     93         static Method getMethodMultipleAnnotationExplicitSingle() throws Exception {
     94             return AnnotatedMethodClass.class.getDeclaredMethod(
     95                     "multipleAnnotationExplicitSingle", String.class);
     96         }
     97 
     98         static Method getMethodMultipleAnnotation() throws Exception {
     99             return AnnotatedMethodClass.class.getDeclaredMethod("multipleAnnotation", String.class);
    100         }
    101 
    102         static Method getMethodSingleAnnotation() throws Exception {
    103             return AnnotatedMethodClass.class.getDeclaredMethod("singleAnnotation", String.class);
    104         }
    105 
    106         static Method getMethodStaticSingleAnnotation() throws Exception {
    107             return AnnotatedMethodClass.class.getDeclaredMethod("staticSingleAnnotation",
    108                     String.class);
    109         }
    110     }
    111 
    112     private static abstract class AnnotatedMethodAbstractClass {
    113         abstract void abstractSingleAnnotation(@Repeated(1) String p0);
    114 
    115         static Method getMethodAbstractSingleAnnotation() throws Exception {
    116             return AnnotatedMethodAbstractClass.class.getDeclaredMethod(
    117                     "abstractSingleAnnotation", String.class);
    118         }
    119     }
    120 
    121 
    122     public void testMethodGetParameterAnnotations_repeated() throws Exception {
    123         assertOnlyParameterAnnotations(
    124                 AnnotatedMethodClass.getMethodWithoutAnnotations(), EXPECT_EMPTY);
    125         assertOnlyParameterAnnotations(
    126                 AnnotatedMethodClass.getMethodMultipleAnnotationOddity(),
    127                 "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
    128         assertOnlyParameterAnnotations(
    129                 AnnotatedMethodClass.getMethodMultipleAnnotationExplicitSingle(),
    130                 "@Container({@Repeated(1)})");
    131         assertOnlyParameterAnnotations(
    132                 AnnotatedMethodClass.getMethodMultipleAnnotation(),
    133                 "@Container({@Repeated(1), @Repeated(2)})");
    134         assertOnlyParameterAnnotations(
    135                 AnnotatedMethodClass.getMethodSingleAnnotation(),
    136                 "@Repeated(1)");
    137         assertOnlyParameterAnnotations(
    138                 AnnotatedMethodClass.getMethodStaticSingleAnnotation(),
    139                 "@Repeated(1)");
    140         assertOnlyParameterAnnotations(
    141                 AnnotatedMethodAbstractClass.getMethodAbstractSingleAnnotation(),
    142                 "@Repeated(1)");
    143 
    144     }
    145 
    146     private static class ConstructorClass {
    147         // No annotations.
    148         public ConstructorClass(Integer parameter1, Integer parameter2) {}
    149 
    150         // Annotations.
    151         public ConstructorClass(@AnnotationB @AnnotationD String parameter1,
    152                 @AnnotationC @AnnotationD String parameter2) {}
    153     }
    154 
    155     public void testConstructorGetParameterAnnotations() throws Exception {
    156         Constructor constructorWithoutAnnotatedParameters =
    157                 ConstructorClass.class.getDeclaredConstructor(Integer.class, Integer.class);
    158         Annotation[][] noParameterAnnotations = getParameterAnnotations(
    159                 constructorWithoutAnnotatedParameters, 2);
    160         assertEquals(set(), annotationsToTypes(noParameterAnnotations[0]));
    161         assertEquals(set(), annotationsToTypes(noParameterAnnotations[1]));
    162 
    163         Constructor constructorWithAnnotatedParameters =
    164                 ConstructorClass.class.getDeclaredConstructor(String.class, String.class);
    165         Annotation[][] parameterAnnotations = getParameterAnnotations(
    166                 constructorWithAnnotatedParameters, 2);
    167         assertEquals(set(AnnotationB.class, AnnotationD.class),
    168                 annotationsToTypes(parameterAnnotations[0]));
    169         assertEquals(set(AnnotationC.class, AnnotationD.class),
    170                 annotationsToTypes(parameterAnnotations[1]));
    171     }
    172 
    173     private static class AnnotatedConstructorClass {
    174         public AnnotatedConstructorClass(Boolean p0) {}
    175 
    176         public AnnotatedConstructorClass(
    177                 @Repeated(1) @Container({@Repeated(2), @Repeated(3)}) Long p0) {}
    178 
    179         public AnnotatedConstructorClass(@Container({@Repeated(1)}) Double p0) {}
    180 
    181         public AnnotatedConstructorClass(@Repeated(1) @Repeated(2) Integer p0) {}
    182 
    183         public AnnotatedConstructorClass(@Repeated(1) String p0) {}
    184 
    185         static Constructor<?> getConstructorWithoutAnnotations() throws Exception {
    186             return AnnotatedConstructorClass.class.getDeclaredConstructor(Boolean.class);
    187         }
    188 
    189         static Constructor<?> getConstructorMultipleAnnotationOddity() throws Exception {
    190             return AnnotatedConstructorClass.class.getDeclaredConstructor(Long.class);
    191         }
    192 
    193         static Constructor<?> getConstructorMultipleAnnotationExplicitSingle()
    194                 throws Exception {
    195             return AnnotatedConstructorClass.class.getDeclaredConstructor(Double.class);
    196         }
    197 
    198         static Constructor<?> getConstructorMultipleAnnotation() throws Exception {
    199             return AnnotatedConstructorClass.class.getDeclaredConstructor(Integer.class);
    200         }
    201 
    202         static Constructor<?> getConstructorSingleAnnotation() throws Exception {
    203             return AnnotatedConstructorClass.class.getDeclaredConstructor(String.class);
    204         }
    205     }
    206 
    207     public void testConstructorGetParameterAnnotations_repeated() throws Exception {
    208         assertOnlyParameterAnnotations(
    209                 AnnotatedConstructorClass.getConstructorWithoutAnnotations(),
    210                 EXPECT_EMPTY);
    211         assertOnlyParameterAnnotations(
    212                 AnnotatedConstructorClass.getConstructorMultipleAnnotationOddity(),
    213                 "@Repeated(1)", "@Container({@Repeated(2), @Repeated(3)})");
    214         assertOnlyParameterAnnotations(
    215                 AnnotatedConstructorClass.getConstructorMultipleAnnotationExplicitSingle(),
    216                 "@Container({@Repeated(1)})");
    217         assertOnlyParameterAnnotations(
    218                 AnnotatedConstructorClass.getConstructorMultipleAnnotation(),
    219                 "@Container({@Repeated(1), @Repeated(2)})");
    220         assertOnlyParameterAnnotations(
    221                 AnnotatedConstructorClass.getConstructorSingleAnnotation(),
    222                 "@Repeated(1)");
    223     }
    224 
    225     /**
    226      * As an inner class the constructor will actually have two parameters: the first, referencing
    227      * the enclosing object, is inserted by the compiler.
    228      */
    229     class InnerClass {
    230         InnerClass(@AnnotationA String p1) {}
    231     }
    232 
    233     /** Special case testing for a compiler-generated constructor parameter. JLS 8.8.1, JLS 13.1. */
    234     public void testImplicitConstructorParameters_innerClass() throws Exception {
    235         Constructor<InnerClass> constructor =
    236                 InnerClass.class.getDeclaredConstructor(
    237                         ExecutableParameterTest.class, String.class);
    238 
    239         // The parameter annotation code behaves as if there are two parameters.
    240         Annotation[][] annotations = getParameterAnnotations(constructor, 2);
    241         assertAnnotationsMatch(annotations[0], new String[0]);
    242         assertAnnotationsMatch(annotations[1], new String[] { "@AnnotationA" });
    243     }
    244 
    245     static abstract class AnonymousBaseClass {
    246         public AnonymousBaseClass(@AnnotationA String p1) {}
    247     }
    248 
    249     /** Special case testing for a compiler-generated constructor parameter. JLS 13.1 */
    250     public void testImplicitConstructorParameters_anonymousClass() throws Exception {
    251         /*
    252          * As an anonymous class the constructor will actually have two parameters: the first,
    253          * referencing the enclosing object, is inserted by the compiler.
    254          */
    255         AnonymousBaseClass anonymousClassInstance = new AnonymousBaseClass("p1") {};
    256 
    257         Constructor<? extends AnonymousBaseClass> constructor =
    258                 anonymousClassInstance.getClass().getDeclaredConstructor(
    259                         ExecutableParameterTest.class, String.class);
    260         // The parameter annotation code behaves as if there are two parameters.
    261         Annotation[][] annotations = getParameterAnnotations(constructor, 2);
    262         assertAnnotationsMatch(annotations[0], new String[0]);
    263         assertAnnotationsMatch(annotations[1], new String[0]);
    264     }
    265 
    266     /**
    267      * A static inner / nested member class will not have synthetic parameters and should behave
    268      * like a top-level class.
    269      */
    270     static class StaticInnerClass {
    271         StaticInnerClass(@AnnotationA String p1) {}
    272     }
    273 
    274     /** Special case testing for a compiler-generated constructor parameter. */
    275     public void testImplicitConstructorParameters_staticInnerClass() throws Exception {
    276         Constructor<StaticInnerClass> constructor =
    277                 StaticInnerClass.class.getDeclaredConstructor(String.class);
    278         Parameter[] parameters = constructor.getParameters();
    279         assertEquals(1, parameters.length);
    280 
    281         Annotation[][] annotations = getParameterAnnotations(constructor, 1);
    282         assertAnnotationsMatch(annotations[0], new String[] { "@AnnotationA" });
    283     }
    284 
    285     private static void assertOnlyParameterAnnotations(
    286             Executable executable, String... expectedAnnotationStrings) throws Exception {
    287         Annotation[][] allAnnotations = getParameterAnnotations(executable, 1);
    288 
    289         Annotation[] p0Annotations = allAnnotations[0];
    290         assertAnnotationsMatch(p0Annotations, expectedAnnotationStrings);
    291     }
    292 
    293     private static Annotation[][] getParameterAnnotations(
    294             Executable executable, int expectedParameterAnnotationsSize) {
    295         Annotation[][] allAnnotations = executable.getParameterAnnotations();
    296         assertEquals(expectedParameterAnnotationsSize, allAnnotations.length);
    297         return allAnnotations;
    298     }
    299 }
    300