diff options
Diffstat (limited to 'test/715-clinit-implicit-parameter-annotations/src/Main.java')
-rw-r--r-- | test/715-clinit-implicit-parameter-annotations/src/Main.java | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/test/715-clinit-implicit-parameter-annotations/src/Main.java b/test/715-clinit-implicit-parameter-annotations/src/Main.java new file mode 100644 index 0000000000..351e3a94b3 --- /dev/null +++ b/test/715-clinit-implicit-parameter-annotations/src/Main.java @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.reflect.Constructor; +import java.lang.reflect.Parameter; + +public class Main { + // A simple parameter annotation + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationA {} + + // A parameter annotation with additional state + @Retention(RetentionPolicy.RUNTIME) + public @interface AnnotationB { + String value() default "default-value"; + } + + // An inner class whose constructors with have an implicit + // argument for the enclosing instance. + public class Inner { + private final int number; + private final String text; + boolean flag; + + Inner(@AnnotationA int number, String text) { + this.number = number; + this.text = text; + this.flag = false; + } + + Inner(@AnnotationA int number, String text, @AnnotationB("x") boolean flag) { + this.number = number; + this.text = text; + this.flag = flag; + } + } + + // An inner class whose constructors with have no implicit + // arguments for the enclosing instance. + public static class StaticInner { + private final int number; + private final String text; + boolean flag; + + StaticInner(@AnnotationA int number, String text) { + this.number = number; + this.text = text; + this.flag = false; + } + + StaticInner(@AnnotationB("foo") int number, String text, @AnnotationA boolean flag) { + this.number = number; + this.text = text; + this.flag = flag; + } + } + + public enum ImportantNumber { + ONE(1.0), + TWO(2.0), + MANY(3.0, true); + + private double doubleValue; + private boolean isLarge; + + ImportantNumber(@AnnotationA double doubleValue) { + this.doubleValue = doubleValue; + this.isLarge = false; + } + + ImportantNumber(@AnnotationB("x") double doubleValue, @AnnotationB("y") boolean isLarge) { + this.doubleValue = doubleValue; + this.isLarge = isLarge; + } + } + + public enum BinaryNumber { + ZERO, + ONE; + } + + private abstract static class AnonymousBase { + public AnonymousBase(@AnnotationA String s) {} + } + + private static String annotationToNormalizedString(Annotation annotation) { + // String.replace() to accomodate different representation across VMs. + return annotation.toString().replace("\"", ""); + } + + private static void DumpConstructorParameterAnnotations(Class<?> cls) throws Throwable { + System.out.println(cls.getName()); + for (Constructor c : cls.getDeclaredConstructors()) { + System.out.println(" " + c); + Annotation[][] annotations = c.getParameterAnnotations(); + Parameter[] parameters = c.getParameters(); + for (int i = 0; i < annotations.length; ++i) { + // Exercise java.lang.reflect.Executable.getParameterAnnotationsNative() + // which retrieves all annotations for the parameters. + System.out.print(" Parameter [" + i + "]:"); + for (Annotation annotation : parameters[i].getAnnotations()) { + System.out.println(" Indexed : " + annotationToNormalizedString(annotation)); + } + for (Annotation annotation : annotations[i]) { + System.out.println(" Array : " + annotationToNormalizedString(annotation)); + } + + // Exercise Parameter.getAnnotationNative() with + // retrieves a single parameter annotation according to type. + Object[] opaqueClasses = new Object[] {AnnotationA.class, AnnotationB.class}; + for (Object opaqueClass : opaqueClasses) { + @SuppressWarnings("unchecked") + Class<? extends Annotation> annotationClass = + (Class<? extends Annotation>) opaqueClass; + Annotation annotation = parameters[i].getDeclaredAnnotation(annotationClass); + String hasAnnotation = (annotation != null ? "Yes" : "No"); + System.out.println(" " + annotationClass.getName() + " " + hasAnnotation); + + Annotation[] parameterAnnotations = parameters[i].getDeclaredAnnotationsByType(annotationClass); + for (Annotation parameterAnnotation : parameterAnnotations) { + System.out.println(" " + annotationToNormalizedString(parameterAnnotation)); + } + } + } + } + } + + private Class<?> getLocalClassWithEnclosingInstanceCapture() { + class LocalClass { + private final int integerValue; + + LocalClass(@AnnotationA int integerValue) { + this.integerValue = integerValue; + } + } + return LocalClass.class; + } + + private Class<?> getLocalClassWithEnclosingInstanceAndLocalCapture() { + final long CAPTURED_VALUE = System.currentTimeMillis(); + class LocalClassWithCapture { + private final String value; + private final long capturedValue; + + LocalClassWithCapture(@AnnotationA String p1) { + this.value = p1; + this.capturedValue = CAPTURED_VALUE; + } + } + return LocalClassWithCapture.class; + } + + public static void main(String[] args) throws Throwable { + // A local class declared in a static context (0 implicit parameters). + class LocalClassStaticContext { + private final int value; + + LocalClassStaticContext(@AnnotationA int p0) { + this.value = p0; + } + } + + final long CAPTURED_VALUE = System.currentTimeMillis(); + // A local class declared in a static context with a capture (1 implicit parameters). + class LocalClassStaticContextWithCapture { + private final long capturedValue; + private final String argumentValue; + + LocalClassStaticContextWithCapture(@AnnotationA String p1) { + this.capturedValue = CAPTURED_VALUE; + this.argumentValue = p1; + } + } + + // Another local class declared in a static context with a capture (1 implicit parameters). + class LocalClassStaticContextWithCaptureAlternateOrdering { + private final String argumentValue; + private final long capturedValue; + + LocalClassStaticContextWithCaptureAlternateOrdering(@AnnotationA String p1) { + this.argumentValue = p1; + this.capturedValue = CAPTURED_VALUE; + } + } + + DumpConstructorParameterAnnotations(Main.class); + DumpConstructorParameterAnnotations(LocalClassStaticContext.class); + DumpConstructorParameterAnnotations(LocalClassStaticContextWithCapture.class); + DumpConstructorParameterAnnotations(LocalClassStaticContextWithCaptureAlternateOrdering.class); + Main m = new Main(); + DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceCapture()); + DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceAndLocalCapture()); + DumpConstructorParameterAnnotations(Inner.class); + DumpConstructorParameterAnnotations(StaticInner.class); + DumpConstructorParameterAnnotations(ImportantNumber.class); + DumpConstructorParameterAnnotations(BinaryNumber.class); + DumpConstructorParameterAnnotations(new AnonymousBase("") {}.getClass()); + } +} |