blob: ee369769ca9a29d476dc155d28d5a35382561d22 [file] [log] [blame]
/*
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8074977
* @summary Test consistency of annotations on constructor parameters
* @compile TestConstructorParameterTypeAnnotations.java
* @run main TestConstructorParameterTypeAnnotations
* @compile -parameters TestConstructorParameterTypeAnnotations.java
* @run main TestConstructorParameterTypeAnnotations
*/
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
/*
* Some constructor parameters are <em>mandated</em>; that is, they
* are not explicitly present in the source code, but required to be
* present by the Java Language Specification. In other cases, some
* constructor parameters are not present in the source, but are
* synthesized by the compiler as an implementation artifact. There is
* not a reliable mechanism to consistently determine whether or not
* a parameter is implicit or not.
*
* (Using the "-parameters" option to javac does emit the information
* needed to make a reliably determination, but the information is not
* present by default.)
*
* The lack of such a mechanism causes complications reading parameter
* annotations in some cases since annotations for parameters are
* written out for the parameters in the source code, but when reading
* annotations at runtime all the parameters, including implicit ones,
* are present.
*/
public class TestConstructorParameterTypeAnnotations {
public static void main(String... args) {
int errors = 0;
Class<?>[] classes = {NestedClass0.class,
NestedClass1.class,
NestedClass2.class,
NestedClass3.class,
NestedClass4.class,
StaticNestedClass0.class,
StaticNestedClass1.class,
StaticNestedClass2.class };
for (Class<?> clazz : classes) {
for (Constructor<?> ctor : clazz.getConstructors()) {
System.out.println(ctor);
errors += checkGetParameterAnnotations(clazz, ctor);
errors += checkGetAnnotatedParametersGetAnnotation(clazz, ctor);
}
}
if (errors > 0)
throw new RuntimeException(errors + " errors.");
return;
}
private static int checkGetParameterAnnotations(Class<?> clazz,
Constructor<?> ctor) {
String annotationString =
Arrays.deepToString(ctor.getParameterAnnotations());
String expectedString =
clazz.getAnnotation(ExpectedGetParameterAnnotations.class).value();
if (!Objects.equals(annotationString, expectedString)) {
System.err.println("Annotation mismatch on " + ctor +
"\n\tExpected:" + expectedString +
"\n\tActual: " + annotationString);
return 1;
}
return 0;
}
private static int checkGetAnnotatedParametersGetAnnotation(Class<?> clazz,
Constructor<?> ctor) {
int errors = 0;
int i = 0;
ExpectedParameterTypeAnnotations epa =
clazz.getAnnotation(ExpectedParameterTypeAnnotations.class);
for (AnnotatedType param : ctor.getAnnotatedParameterTypes() ) {
String annotationString =
Objects.toString(param.getAnnotation(MarkerTypeAnnotation.class));
String expectedString = epa.value()[i];
if (!Objects.equals(annotationString, expectedString)) {
System.err.println("Annotation mismatch on " + ctor +
" on param " + param +
"\n\tExpected:" + expectedString +
"\n\tActual: " + annotationString);
errors++;
}
i++;
}
return errors;
}
@ExpectedGetParameterAnnotations("[[]]")
@ExpectedParameterTypeAnnotations({"null"})
public class NestedClass0 {
public NestedClass0() {}
}
@ExpectedGetParameterAnnotations("[[], []]")
@ExpectedParameterTypeAnnotations({
"null",
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=1)"})
public class NestedClass1 {
public NestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
}
@ExpectedGetParameterAnnotations("[[], [], []]")
@ExpectedParameterTypeAnnotations({
"null",
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=2)",
"null"})
public class NestedClass2 {
public NestedClass2(@MarkerTypeAnnotation(2) int parameter1,
int parameter2) {}
}
@ExpectedGetParameterAnnotations("[[], [], []]")
@ExpectedParameterTypeAnnotations({
"null",
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=3)",
"null"})
public class NestedClass3 {
public <P> NestedClass3(@MarkerTypeAnnotation(3) P parameter1,
int parameter2) {}
}
@ExpectedGetParameterAnnotations("[[], [], []]")
@ExpectedParameterTypeAnnotations({
"null",
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=4)",
"null"})
public class NestedClass4 {
public <P, Q> NestedClass4(@MarkerTypeAnnotation(4) P parameter1,
Q parameter2) {}
}
@ExpectedGetParameterAnnotations("[]")
@ExpectedParameterTypeAnnotations({"null"})
public static class StaticNestedClass0 {
public StaticNestedClass0() {}
}
@ExpectedGetParameterAnnotations("[[]]")
@ExpectedParameterTypeAnnotations({
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=1)"})
public static class StaticNestedClass1 {
public StaticNestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
}
@ExpectedGetParameterAnnotations("[[], []]")
@ExpectedParameterTypeAnnotations({
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=2)",
"null"})
public static class StaticNestedClass2 {
public StaticNestedClass2(@MarkerTypeAnnotation(2) int parameter1,
int parameter2) {}
}
@ExpectedGetParameterAnnotations("[[], []]")
@ExpectedParameterTypeAnnotations({
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=3)",
"null"})
public static class StaticNestedClass3 {
public <P> StaticNestedClass3(@MarkerTypeAnnotation(3) P parameter1,
int parameter2) {}
}
@ExpectedGetParameterAnnotations("[[], []]")
@ExpectedParameterTypeAnnotations({
"@TestConstructorParameterTypeAnnotations$MarkerTypeAnnotation(value=4)",
"null"})
public static class StaticNestedClass4 {
public <P, Q> StaticNestedClass4(@MarkerTypeAnnotation(4) P parameter1,
Q parameter2) {}
}
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
@interface MarkerTypeAnnotation {
int value();
}
/**
* String form of expected value of calling
* getParameterAnnotations on a constructor.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ExpectedGetParameterAnnotations {
String value();
}
/**
* String form of expected value of calling
* getAnnotation(MarkerTypeAnnotation.class) on each element of the
* result of getParameters() on a constructor.
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface ExpectedParameterTypeAnnotations {
String[] value();
}
}