undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
321
test/jdk/java/lang/annotation/AnnotationToStringTest.java
Normal file
321
test/jdk/java/lang/annotation/AnnotationToStringTest.java
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2024, 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 8162817 8168921 8322218
|
||||
* @summary Test of toString on normal annotations
|
||||
*/
|
||||
|
||||
// See also the sibling compile-time test
|
||||
// test/langtools/tools/javac/processing/model/element/AnnotationToStringTest.java
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.Field;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The expected string values are stored in @ExpectedString
|
||||
* annotations. The essence of the test is comparing the toString()
|
||||
* result of annotations to the corresponding ExpectedString.value().
|
||||
*/
|
||||
|
||||
public class AnnotationToStringTest {
|
||||
public static void main(String... args) throws Exception {
|
||||
int failures = 0;
|
||||
|
||||
failures += check(PrimHost.class.getAnnotation(ExpectedString.class).value(),
|
||||
PrimHost.class.getAnnotation(MostlyPrimitive.class).toString());
|
||||
failures += classyTest();
|
||||
failures += arrayAnnotationTest();
|
||||
|
||||
if (failures > 0)
|
||||
throw new RuntimeException(failures + " failures");
|
||||
}
|
||||
|
||||
private static int check(String expected, String actual) {
|
||||
if (!expected.equals(actual)) {
|
||||
System.err.printf("ERROR: Expected ''%s'';%ngot ''%s''.\n",
|
||||
expected, actual);
|
||||
return 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ExpectedString(
|
||||
"@MostlyPrimitive(c0='a', "+
|
||||
"c1='\\'', " +
|
||||
"b0=(byte)0x01, " +
|
||||
"i0=1, " +
|
||||
"i1=2, " +
|
||||
"f0=1.0f, " +
|
||||
"f1=0.0f/0.0f, " +
|
||||
"d0=0.0, " +
|
||||
"d1=1.0/0.0, " +
|
||||
"l0=5L, " +
|
||||
"l1=9223372036854775807L, " +
|
||||
"l2=-9223372036854775808L, " +
|
||||
"l3=-2147483648L, " +
|
||||
"s0=\"Hello world.\", " +
|
||||
"s1=\"a\\\"b\", " +
|
||||
"class0=Obj[].class, " +
|
||||
"classArray={Obj[].class})")
|
||||
@MostlyPrimitive(
|
||||
c0='a',
|
||||
c1='\'',
|
||||
b0=1,
|
||||
i0=1,
|
||||
i1=2,
|
||||
f0=1.0f,
|
||||
f1=Float.NaN,
|
||||
d0=0.0,
|
||||
d1=2.0/0.0,
|
||||
l0=5,
|
||||
l1=Long.MAX_VALUE,
|
||||
l2=Long.MIN_VALUE,
|
||||
l3=Integer.MIN_VALUE,
|
||||
s0="Hello world.",
|
||||
s1="a\"b",
|
||||
class0=Obj[].class,
|
||||
classArray={Obj[].class}
|
||||
)
|
||||
static class PrimHost{}
|
||||
|
||||
private static int classyTest() {
|
||||
int failures = 0;
|
||||
for (Field f : AnnotationHost.class.getFields()) {
|
||||
Annotation a = f.getAnnotation(Classy.class);
|
||||
System.out.println(a);
|
||||
failures += check(f.getAnnotation(ExpectedString.class).value(),
|
||||
a.toString());
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
static class AnnotationHost {
|
||||
@ExpectedString(
|
||||
"@Classy(Obj.class)")
|
||||
@Classy(Obj.class)
|
||||
public int f0;
|
||||
|
||||
@ExpectedString(
|
||||
"@Classy(Obj[].class)")
|
||||
@Classy(Obj[].class)
|
||||
public int f1;
|
||||
|
||||
@ExpectedString(
|
||||
"@Classy(Obj[][].class)")
|
||||
@Classy(Obj[][].class)
|
||||
public int f2;
|
||||
|
||||
@ExpectedString(
|
||||
"@Classy(Obj[][][].class)")
|
||||
@Classy(Obj[][][].class)
|
||||
public int f3;
|
||||
|
||||
@ExpectedString(
|
||||
"@Classy(int.class)")
|
||||
@Classy(int.class)
|
||||
public int f4;
|
||||
|
||||
@ExpectedString(
|
||||
"@Classy(int[][][].class)")
|
||||
@Classy(int[][][].class)
|
||||
public int f5;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each field should have two annotations, the first being
|
||||
* @ExpectedString and the second the annotation under test.
|
||||
*/
|
||||
private static int arrayAnnotationTest() {
|
||||
int failures = 0;
|
||||
for (Field f : ArrayAnnotationHost.class.getFields()) {
|
||||
Annotation[] annotations = f.getAnnotations();
|
||||
System.out.println(annotations[1]);
|
||||
failures += check(((ExpectedString)annotations[0]).value(),
|
||||
annotations[1].toString());
|
||||
}
|
||||
return failures;
|
||||
}
|
||||
|
||||
static class ArrayAnnotationHost {
|
||||
@ExpectedString(
|
||||
"@EnumValue(NON_SEALED)") // toString and name differ
|
||||
@EnumValue(Modifier.NON_SEALED)
|
||||
public int f00;
|
||||
|
||||
@ExpectedString(
|
||||
"@BooleanArray({true, false, true})")
|
||||
@BooleanArray({true, false, true})
|
||||
public boolean[] f0;
|
||||
|
||||
@ExpectedString(
|
||||
"@FloatArray({3.0f, 4.0f, 0.0f/0.0f, -1.0f/0.0f, 1.0f/0.0f})")
|
||||
@FloatArray({3.0f, 4.0f, Float.NaN, Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY})
|
||||
public float[] f1;
|
||||
|
||||
@ExpectedString(
|
||||
"@DoubleArray({1.0, 2.0, 0.0/0.0, 1.0/0.0, -1.0/0.0})")
|
||||
@DoubleArray({1.0, 2.0, Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY,})
|
||||
public double[] f2;
|
||||
|
||||
@ExpectedString(
|
||||
"@ByteArray({(byte)0x0a, (byte)0x0b, (byte)0x0c})")
|
||||
@ByteArray({10, 11, 12})
|
||||
public byte[] f3;
|
||||
|
||||
@ExpectedString(
|
||||
"@ShortArray({0, 4, 5})")
|
||||
@ShortArray({0, 4, 5})
|
||||
public short[] f4;
|
||||
|
||||
@ExpectedString(
|
||||
"@CharArray({'a', 'b', 'c', '\\'', '\"'})")
|
||||
@CharArray({'a', 'b', 'c', '\'', '"'})
|
||||
public char[] f5;
|
||||
|
||||
@ExpectedString(
|
||||
"@IntArray({1})")
|
||||
@IntArray({1})
|
||||
public int[] f6;
|
||||
|
||||
@ExpectedString(
|
||||
"@LongArray({-9223372036854775808L, -2147483649L, -2147483648L," +
|
||||
" -2147483647L, 2147483648L, 9223372036854775807L})")
|
||||
@LongArray({Long.MIN_VALUE, Integer.MIN_VALUE-1L, Integer.MIN_VALUE,
|
||||
-Integer.MAX_VALUE, Integer.MAX_VALUE+1L, Long.MAX_VALUE})
|
||||
public long[] f7;
|
||||
|
||||
@ExpectedString(
|
||||
"@StringArray({\"A\", \"B\", \"C\", \"\\\"Quote\\\"\", \"'\", \"\\\"\"})")
|
||||
@StringArray({"A", "B", "C", "\"Quote\"", "'", "\""})
|
||||
public String[] f8;
|
||||
|
||||
@ExpectedString(
|
||||
"@ClassArray({int.class, Obj[].class})")
|
||||
@ClassArray({int.class, Obj[].class})
|
||||
public Class<?>[] f9;
|
||||
|
||||
@ExpectedString(
|
||||
"@EnumArray({SEALED, NON_SEALED, PUBLIC})")
|
||||
@EnumArray({Modifier.SEALED, Modifier.NON_SEALED, Modifier.PUBLIC})
|
||||
public RetentionPolicy[] f10;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------ Supporting types ------------
|
||||
|
||||
class Obj {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface EnumValue {
|
||||
Modifier value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExpectedString {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Classy {
|
||||
Class<?> value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface BooleanArray {
|
||||
boolean[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface FloatArray {
|
||||
float[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface DoubleArray {
|
||||
double[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ByteArray {
|
||||
byte[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ShortArray {
|
||||
short[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface CharArray {
|
||||
char[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface IntArray {
|
||||
int[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface LongArray {
|
||||
long[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ClassArray {
|
||||
Class<?>[] value() default {int.class, Obj[].class};
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface StringArray {
|
||||
String[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface EnumArray {
|
||||
Modifier[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface MostlyPrimitive {
|
||||
char c0();
|
||||
char c1();
|
||||
byte b0();
|
||||
int i0();
|
||||
int i1();
|
||||
float f0();
|
||||
float f1();
|
||||
double d0();
|
||||
double d1();
|
||||
long l0();
|
||||
long l1();
|
||||
long l2();
|
||||
long l3();
|
||||
String s0();
|
||||
String s1();
|
||||
Class<?> class0();
|
||||
Class<?>[] classArray();
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2015, 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 7122142
|
||||
* @summary Test deadlock situation when recursive annotations are parsed
|
||||
* @modules java.management
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
public class AnnotationTypeDeadlockTest {
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@AnnB
|
||||
public @interface AnnA {
|
||||
}
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@AnnA
|
||||
public @interface AnnB {
|
||||
}
|
||||
|
||||
static class Task extends Thread {
|
||||
final CountDownLatch prepareLatch;
|
||||
final AtomicInteger goLatch;
|
||||
final Class<?> clazz;
|
||||
|
||||
Task(CountDownLatch prepareLatch, AtomicInteger goLatch, Class<?> clazz) {
|
||||
super(clazz.getSimpleName());
|
||||
setDaemon(true); // in case it deadlocks
|
||||
this.prepareLatch = prepareLatch;
|
||||
this.goLatch = goLatch;
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
prepareLatch.countDown(); // notify we are prepared
|
||||
while (goLatch.get() > 0); // spin-wait before go
|
||||
clazz.getDeclaredAnnotations();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
CountDownLatch prepareLatch = new CountDownLatch(2);
|
||||
AtomicInteger goLatch = new AtomicInteger(1);
|
||||
Task taskA = new Task(prepareLatch, goLatch, AnnA.class);
|
||||
Task taskB = new Task(prepareLatch, goLatch, AnnB.class);
|
||||
taskA.start();
|
||||
taskB.start();
|
||||
// wait until both threads start-up
|
||||
prepareLatch.await();
|
||||
// let them go
|
||||
goLatch.set(0);
|
||||
// obtain ThreadMXBean
|
||||
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
|
||||
// wait for threads to finish or dead-lock
|
||||
while (taskA.isAlive() || taskB.isAlive()) {
|
||||
// attempt to join threads
|
||||
taskA.join(500L);
|
||||
taskB.join(500L);
|
||||
// detect dead-lock
|
||||
long[] deadlockedIds = threadBean.findMonitorDeadlockedThreads();
|
||||
if (deadlockedIds != null && deadlockedIds.length > 0) {
|
||||
StringBuilder sb = new StringBuilder("deadlock detected:\n\n");
|
||||
for (ThreadInfo ti : threadBean.getThreadInfo(deadlockedIds, Integer.MAX_VALUE)) {
|
||||
sb.append(ti);
|
||||
}
|
||||
throw new IllegalStateException(sb.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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
|
||||
* @summary Test consistent parsing of ex-RUNTIME annotations that
|
||||
* were changed and separately compiled to have CLASS retention
|
||||
* @run main AnnotationTypeRuntimeAssumptionTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.CLASS;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
/**
|
||||
* This test simulates a situation where there are two mutually recursive
|
||||
* {@link RetentionPolicy#RUNTIME RUNTIME} annotations {@link AnnA_v1 AnnA_v1}
|
||||
* and {@link AnnB AnnB} and then the first is changed to have
|
||||
* {@link RetentionPolicy#CLASS CLASS} retention and separately compiled.
|
||||
* When {@link AnnA_v1 AnnA_v1} annotation is looked-up on {@link AnnB AnnB}
|
||||
* it still appears to have {@link RetentionPolicy#RUNTIME RUNTIME} retention.
|
||||
*/
|
||||
public class AnnotationTypeRuntimeAssumptionTest {
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@AnnB
|
||||
public @interface AnnA_v1 {
|
||||
}
|
||||
|
||||
// An alternative version of AnnA_v1 with CLASS retention instead.
|
||||
// Used to simulate separate compilation (see AltClassLoader below).
|
||||
@Retention(CLASS)
|
||||
@AnnB
|
||||
public @interface AnnA_v2 {
|
||||
}
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@AnnA_v1
|
||||
public @interface AnnB {
|
||||
}
|
||||
|
||||
@AnnA_v1
|
||||
public static class TestTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
AnnA_v1 ann1 = TestTask.class.getDeclaredAnnotation(AnnA_v1.class);
|
||||
if (ann1 != null) {
|
||||
throw new IllegalStateException(
|
||||
"@" + ann1.annotationType().getSimpleName() +
|
||||
" found on: " + TestTask.class.getName() +
|
||||
" should not be visible at runtime");
|
||||
}
|
||||
AnnA_v1 ann2 = AnnB.class.getDeclaredAnnotation(AnnA_v1.class);
|
||||
if (ann2 != null) {
|
||||
throw new IllegalStateException(
|
||||
"@" + ann2.annotationType().getSimpleName() +
|
||||
" found on: " + AnnB.class.getName() +
|
||||
" should not be visible at runtime");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ClassLoader altLoader = new AltClassLoader(
|
||||
AnnotationTypeRuntimeAssumptionTest.class.getClassLoader());
|
||||
|
||||
Runnable altTask = (Runnable) Class.forName(
|
||||
TestTask.class.getName(),
|
||||
true,
|
||||
altLoader).newInstance();
|
||||
|
||||
altTask.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* A ClassLoader implementation that loads alternative implementations of
|
||||
* classes. If class name ends with "_v1" it locates instead a class with
|
||||
* name ending with "_v2" and loads that class instead.
|
||||
*/
|
||||
static class AltClassLoader extends ClassLoader {
|
||||
AltClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> loadClass(String name, boolean resolve)
|
||||
throws ClassNotFoundException {
|
||||
if (name.indexOf('.') < 0) { // root package is our class
|
||||
synchronized (getClassLoadingLock(name)) {
|
||||
// First, check if the class has already been loaded
|
||||
Class<?> c = findLoadedClass(name);
|
||||
if (c == null) {
|
||||
c = findClass(name);
|
||||
}
|
||||
if (resolve) {
|
||||
resolveClass(c);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
else { // not our class
|
||||
return super.loadClass(name, resolve);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?> findClass(String name)
|
||||
throws ClassNotFoundException {
|
||||
// special class name -> replace it with alternative name
|
||||
if (name.endsWith("_v1")) {
|
||||
String altName = name.substring(0, name.length() - 3) + "_v2";
|
||||
String altPath = altName.replace('.', '/').concat(".class");
|
||||
try (InputStream is = getResourceAsStream(altPath)) {
|
||||
if (is != null) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
// patch class bytes to contain original name
|
||||
for (int i = 0; i < bytes.length - 2; i++) {
|
||||
if (bytes[i] == '_' &&
|
||||
bytes[i + 1] == 'v' &&
|
||||
bytes[i + 2] == '2') {
|
||||
bytes[i + 2] = '1';
|
||||
}
|
||||
}
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
else {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new ClassNotFoundException(name, e);
|
||||
}
|
||||
}
|
||||
else { // not special class name -> just load the class
|
||||
String path = name.replace('.', '/').concat(".class");
|
||||
try (InputStream is = getResourceAsStream(path)) {
|
||||
if (is != null) {
|
||||
byte[] bytes = is.readAllBytes();
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
else {
|
||||
throw new ClassNotFoundException(name);
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new ClassNotFoundException(name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2024, 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 8228988 8266598
|
||||
* @summary An annotation-typed property of an annotation that is represented as an
|
||||
* incompatible property of another type should yield an AnnotationTypeMismatchException.
|
||||
* @run main AnnotationTypeMismatchTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.AnnotationTypeMismatchException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.classfile.Annotation;
|
||||
import java.lang.classfile.AnnotationElement;
|
||||
import java.lang.classfile.AnnotationValue;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||
|
||||
public class AnnotationTypeMismatchTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
/*
|
||||
* @AnAnnotation(value = AnEnum.VALUE) // would now be: value = @Value
|
||||
* class Carrier { }
|
||||
*/
|
||||
byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(
|
||||
AnAnnotation.class.describeConstable().orElseThrow(),
|
||||
AnnotationElement.of("value", AnnotationValue.of(AnEnum.VALUE))
|
||||
)
|
||||
));
|
||||
});
|
||||
ByteArrayClassLoader cl = new ByteArrayClassLoader(AnnotationTypeMismatchTest.class.getClassLoader());
|
||||
cl.init(b);
|
||||
AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class);
|
||||
try {
|
||||
Value value = sample.value();
|
||||
throw new IllegalStateException("Found value: " + value);
|
||||
} catch (AnnotationTypeMismatchException e) {
|
||||
if (!e.element().getName().equals("value")) {
|
||||
throw new IllegalStateException("Unexpected element: " + e.element());
|
||||
} else if (!e.foundType().equals(AnEnum.class.getName() + "." + AnEnum.VALUE.name())) {
|
||||
throw new IllegalStateException("Unexpected type: " + e.foundType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AnEnum {
|
||||
VALUE
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnAnnotation {
|
||||
Value value() default @Value;
|
||||
}
|
||||
|
||||
public @interface Value { }
|
||||
|
||||
public static class ByteArrayClassLoader extends ClassLoader {
|
||||
|
||||
public ByteArrayClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public void init(byte[] b) {
|
||||
defineClass("sample.Carrier", b, 0, b.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2024, 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 8266791
|
||||
* @summary Annotation property which is compiled as an array property but
|
||||
* changed observed as a singular element should throw an
|
||||
* AnnotationTypeMismatchException
|
||||
* @run main ArityTypeMismatchTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.AnnotationTypeMismatchException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.classfile.Annotation;
|
||||
import java.lang.classfile.AnnotationElement;
|
||||
import java.lang.classfile.AnnotationValue;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||
|
||||
public class ArityTypeMismatchTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
/*
|
||||
* This test creates an annotation with a member with a non-array type where the annotation
|
||||
* defines an array property of this type. This can happen if the annotation class is recompiled
|
||||
* without recompiling the code that declares an annotation of this type. In the example, a
|
||||
* class is defined to be annotated as
|
||||
*
|
||||
* @AnAnnotation(value = {"v"}) // should no longer be an array
|
||||
* class Carrier { }
|
||||
*
|
||||
* where @AnAnnotation expects a singular value.
|
||||
*/
|
||||
byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(
|
||||
AnAnnotation.class.describeConstable().orElseThrow(),
|
||||
AnnotationElement.of("value", AnnotationValue.of(new String[] {"v"}))
|
||||
)
|
||||
));
|
||||
});
|
||||
ByteArrayClassLoader cl = new ByteArrayClassLoader(ArityTypeMismatchTest.class.getClassLoader());
|
||||
cl.init(b);
|
||||
AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class);
|
||||
try {
|
||||
String value = sample.value();
|
||||
throw new IllegalStateException("Found value: " + value);
|
||||
} catch (AnnotationTypeMismatchException e) {
|
||||
if (!e.element().getName().equals("value")) {
|
||||
throw new IllegalStateException("Unexpected element: " + e.element());
|
||||
} else if (!e.foundType().equals("Array with component tag: s")) {
|
||||
throw new IllegalStateException("Unexpected type: " + e.foundType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnAnnotation {
|
||||
String value();
|
||||
}
|
||||
|
||||
public static class ByteArrayClassLoader extends ClassLoader {
|
||||
|
||||
public ByteArrayClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public void init(byte[] b) {
|
||||
defineClass("sample.Carrier", b, 0, b.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2024, 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 8266766
|
||||
* @summary An array property of a type that is no longer of a type that is a legal member of an
|
||||
* annotation should throw an AnnotationTypeMismatchException.
|
||||
* @run main ArrayTypeMismatchTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.AnnotationTypeMismatchException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.classfile.AnnotationElement;
|
||||
import java.lang.classfile.AnnotationValue;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import static java.lang.classfile.ClassFile.ACC_ABSTRACT;
|
||||
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
|
||||
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||
|
||||
public class ArrayTypeMismatchTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
/*
|
||||
* This test creates an annotation where the annotation member's type is an array with
|
||||
* a component type that cannot be legally used for an annotation member. This can happen
|
||||
* if a class is recompiled independencly of the annotation type and linked at runtime
|
||||
* in this new version. For a test, a class is created as:
|
||||
*
|
||||
* package sample;
|
||||
* @Carrier(value = { @NoAnnotation })
|
||||
* class Host { }
|
||||
*
|
||||
* where NoAnnotation is defined as a regular interface and not as an annotation type.
|
||||
* The classes are created by using ASM to emulate this state.
|
||||
*/
|
||||
ByteArrayClassLoader cl = new ByteArrayClassLoader(NoAnnotation.class.getClassLoader());
|
||||
cl.init(annotationType(), carrierType());
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends Annotation> host = (Class<? extends Annotation>) cl.loadClass("sample.Host");
|
||||
Annotation sample = cl.loadClass("sample.Carrier").getAnnotation(host);
|
||||
try {
|
||||
Object value = host.getMethod("value").invoke(sample);
|
||||
throw new IllegalStateException("Found value: " + value);
|
||||
} catch (InvocationTargetException ite) {
|
||||
Throwable cause = ite.getCause();
|
||||
if (cause instanceof AnnotationTypeMismatchException e) {
|
||||
if (!e.element().getName().equals("value")) {
|
||||
throw new IllegalStateException("Unexpected element: " + e.element());
|
||||
} else if (!e.foundType().equals("Array with component tag: @")) {
|
||||
throw new IllegalStateException("Unexpected type: " + e.foundType());
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException(cause);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] carrierType() {
|
||||
return ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
var badAnnotationArray = AnnotationValue.ofArray(AnnotationValue.ofAnnotation(
|
||||
java.lang.classfile.Annotation.of(
|
||||
NoAnnotation.class.describeConstable().orElseThrow()
|
||||
)));
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
java.lang.classfile.Annotation.of(ClassDesc.of("sample", "Host"),
|
||||
AnnotationElement.of("value", badAnnotationArray)
|
||||
)
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
private static byte[] annotationType() {
|
||||
return ClassFile.of().build(ClassDesc.of("sample", "Host"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(Annotation.class.describeConstable().orElseThrow());
|
||||
clb.withFlags(AccessFlag.PUBLIC, AccessFlag.ABSTRACT, AccessFlag.INTERFACE,
|
||||
AccessFlag.ANNOTATION);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
java.lang.classfile.Annotation.of(
|
||||
Retention.class.describeConstable().orElseThrow(),
|
||||
AnnotationElement.of("value", AnnotationValue.of(RetentionPolicy.RUNTIME))
|
||||
)
|
||||
));
|
||||
clb.withMethod("value", MethodTypeDesc.of(NoAnnotation[].class.describeConstable()
|
||||
.orElseThrow()), ACC_PUBLIC | ACC_ABSTRACT, mb -> {});
|
||||
});
|
||||
}
|
||||
|
||||
public interface NoAnnotation { }
|
||||
|
||||
public static class ByteArrayClassLoader extends ClassLoader {
|
||||
|
||||
public ByteArrayClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
void init(byte[] annotationType, byte[] carrierType) {
|
||||
defineClass("sample.Host", annotationType, 0, annotationType.length);
|
||||
defineClass("sample.Carrier", carrierType, 0, carrierType.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 2024, 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 8228988 8266598
|
||||
* @summary An enumeration-typed property of an annotation that is represented as an
|
||||
* incompatible property of another type should yield an AnnotationTypeMismatchException.
|
||||
* @run main EnumTypeMismatchTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.AnnotationTypeMismatchException;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.classfile.Annotation;
|
||||
import java.lang.classfile.AnnotationElement;
|
||||
import java.lang.classfile.AnnotationValue;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||
|
||||
public class EnumTypeMismatchTest {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
/*
|
||||
* @AnAnnotation(value = @AnAnnotation) // would now be: value = AnEnum.VALUE
|
||||
* class Carrier { }
|
||||
*/
|
||||
ClassDesc anAnnotationDesc = AnAnnotation.class.describeConstable().orElseThrow();
|
||||
byte[] b = ClassFile.of().build(ClassDesc.of("sample", "Carrier"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(anAnnotationDesc, AnnotationElement.of("value",
|
||||
AnnotationValue.ofAnnotation(Annotation.of(anAnnotationDesc))))
|
||||
));
|
||||
});
|
||||
ByteArrayClassLoader cl = new ByteArrayClassLoader(EnumTypeMismatchTest.class.getClassLoader());
|
||||
cl.init(b);
|
||||
AnAnnotation sample = cl.loadClass("sample.Carrier").getAnnotation(AnAnnotation.class);
|
||||
try {
|
||||
AnEnum value = sample.value();
|
||||
throw new IllegalStateException("Found value: " + value);
|
||||
} catch (AnnotationTypeMismatchException e) {
|
||||
if (!e.element().getName().equals("value")) {
|
||||
throw new IllegalStateException("Unexpected element: " + e.element());
|
||||
} else if (!e.foundType().equals("@" + AnAnnotation.class.getCanonicalName() + "(" + AnEnum.VALUE.name() + ")")) {
|
||||
throw new IllegalStateException("Unexpected type: " + e.foundType());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AnEnum {
|
||||
VALUE
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnAnnotation {
|
||||
AnEnum value() default AnEnum.VALUE;
|
||||
}
|
||||
|
||||
public static class ByteArrayClassLoader extends ClassLoader {
|
||||
|
||||
public ByteArrayClassLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
void init(byte[] b) {
|
||||
defineClass("sample.Carrier", b, 0, b.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 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 6179014
|
||||
* @summary AnnotationTypeMismatchException.foundType method shouldn't loop.
|
||||
* @author Scott Seligman
|
||||
* @run main/timeout=30 FoundType
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
public class FoundType {
|
||||
|
||||
private static final String TYPE = "a.halting.Problem";
|
||||
|
||||
public static void main(String[] args) {
|
||||
AnnotationTypeMismatchException ex =
|
||||
new AnnotationTypeMismatchException(null, TYPE);
|
||||
if (!TYPE.equals(ex.foundType()))
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
419
test/jdk/java/lang/annotation/AnnotationVerifier.java
Normal file
419
test/jdk/java/lang/annotation/AnnotationVerifier.java
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2024, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create class file using ASM, slightly modified the ASMifier output
|
||||
*/
|
||||
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.AnnotationFormatError;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8158510
|
||||
* @summary Verify valid annotation
|
||||
* @modules java.base/sun.reflect.annotation
|
||||
* @clean AnnotationWithVoidReturn AnnotationWithParameter
|
||||
* AnnotationWithExtraInterface AnnotationWithException
|
||||
* AnnotationWithHashCode AnnotationWithDefaultMember
|
||||
* AnnotationWithoutAnnotationAccessModifier HolderX
|
||||
* @compile -XDignore.symbol.file ClassFileGenerator.java GoodAnnotation.java
|
||||
* @run main ClassFileGenerator
|
||||
* @run testng AnnotationVerifier
|
||||
*/
|
||||
|
||||
public class AnnotationVerifier {
|
||||
|
||||
//=======================================================
|
||||
// GoodAnnotation...
|
||||
|
||||
@GoodAnnotation
|
||||
static class HolderA {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderA_goodAnnotation() {
|
||||
testGetAnnotation(HolderA.class, GoodAnnotation.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderA_annotations() {
|
||||
testGetAnnotations(HolderA.class, GoodAnnotation.class);
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithParameter...
|
||||
|
||||
/*
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithParameter {
|
||||
int m(int x) default -1;
|
||||
}
|
||||
*/
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithParameter
|
||||
static class HolderB {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderB_annotationWithParameter() {
|
||||
testGetAnnotation(HolderB.class, AnnotationWithParameter.class, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderB_goodAnnotation() {
|
||||
testGetAnnotation(HolderB.class, GoodAnnotation.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderB_annotations() {
|
||||
testGetAnnotations(HolderB.class, GoodAnnotation.class);
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithVoidReturn...
|
||||
|
||||
/*
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithVoidReturn {
|
||||
void m() default 1;
|
||||
}
|
||||
*/
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithVoidReturn
|
||||
static class HolderC {
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderC_annotationWithVoidReturn() {
|
||||
testGetAnnotation(HolderC.class, AnnotationWithVoidReturn.class, false);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderC_goodAnnotation() {
|
||||
testGetAnnotation(HolderC.class, GoodAnnotation.class, false);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderC_annotations() {
|
||||
testGetAnnotations(HolderC.class);
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithExtraInterface...
|
||||
|
||||
/*
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithExtraInterface extends java.io.Serializable {
|
||||
int m() default 1;
|
||||
}
|
||||
*/
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithExtraInterface
|
||||
static class HolderD {
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderD_annotationWithExtraInterface() {
|
||||
testGetAnnotation(HolderD.class, AnnotationWithExtraInterface.class, false);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderD_goodAnnotation() {
|
||||
testGetAnnotation(HolderD.class, GoodAnnotation.class, false);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderD_annotations() {
|
||||
testGetAnnotations(HolderD.class);
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithException...
|
||||
|
||||
/*
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithException {
|
||||
int m() throws Exception default 1;
|
||||
}
|
||||
*/
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithException
|
||||
static class HolderE {
|
||||
}
|
||||
|
||||
@AnnotationWithException
|
||||
static class HolderE2 {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderE_annotationWithException() {
|
||||
testGetAnnotation(HolderE.class, AnnotationWithException.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderE_goodAnnotation() {
|
||||
testGetAnnotation(HolderE.class, GoodAnnotation.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderE_annotations() {
|
||||
testGetAnnotations(HolderE.class, GoodAnnotation.class, AnnotationWithException.class);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderE_annotationWithException_equals() {
|
||||
AnnotationWithException ann1, ann2;
|
||||
try {
|
||||
ann1 = HolderE.class.getAnnotation(AnnotationWithException.class);
|
||||
ann2 = HolderE2.class.getAnnotation(AnnotationWithException.class);
|
||||
} catch (Throwable t) {
|
||||
throw new AssertionError("Unexpected exception", t);
|
||||
}
|
||||
Assert.assertNotNull(ann1);
|
||||
Assert.assertNotNull(ann2);
|
||||
|
||||
testEquals(ann1, ann2, true); // this throws AnnotationFormatError
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithHashCode...
|
||||
|
||||
/*
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithHashCode {
|
||||
int hashCode() default 1;
|
||||
}
|
||||
*/
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithHashCode
|
||||
static class HolderF {
|
||||
}
|
||||
|
||||
@AnnotationWithHashCode
|
||||
static class HolderF2 {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderF_annotationWithHashCode() {
|
||||
testGetAnnotation(HolderF.class, AnnotationWithHashCode.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderF_goodAnnotation() {
|
||||
testGetAnnotation(HolderF.class, GoodAnnotation.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderF_annotations() {
|
||||
testGetAnnotations(HolderF.class, GoodAnnotation.class, AnnotationWithHashCode.class);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderF_annotationWithHashCode_equals() {
|
||||
AnnotationWithHashCode ann1, ann2;
|
||||
try {
|
||||
ann1 = HolderF.class.getAnnotation(AnnotationWithHashCode.class);
|
||||
ann2 = HolderF2.class.getAnnotation(AnnotationWithHashCode.class);
|
||||
} catch (Throwable t) {
|
||||
throw new AssertionError("Unexpected exception", t);
|
||||
}
|
||||
Assert.assertNotNull(ann1);
|
||||
Assert.assertNotNull(ann2);
|
||||
|
||||
testEquals(ann1, ann2, true); // this throws AnnotationFormatError
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithDefaultMember...
|
||||
|
||||
/*
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithDefaultMember {
|
||||
int m() default 1;
|
||||
default int d() default 2 { return 2; }
|
||||
}
|
||||
*/
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithDefaultMember
|
||||
static class HolderG {
|
||||
}
|
||||
|
||||
@AnnotationWithDefaultMember
|
||||
static class HolderG2 {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderG_annotationWithDefaultMember() {
|
||||
testGetAnnotation(HolderG.class, AnnotationWithDefaultMember.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderG_goodAnnotation() {
|
||||
testGetAnnotation(HolderG.class, GoodAnnotation.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderG_annotations() {
|
||||
testGetAnnotations(HolderG.class, GoodAnnotation.class, AnnotationWithDefaultMember.class);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = AnnotationFormatError.class)
|
||||
public void holderG_annotationWithDefaultMember_equals() {
|
||||
AnnotationWithDefaultMember ann1, ann2;
|
||||
try {
|
||||
ann1 = HolderG.class.getAnnotation(AnnotationWithDefaultMember.class);
|
||||
ann2 = HolderG2.class.getAnnotation(AnnotationWithDefaultMember.class);
|
||||
} catch (Throwable t) {
|
||||
throw new AssertionError("Unexpected exception", t);
|
||||
}
|
||||
Assert.assertNotNull(ann1);
|
||||
Assert.assertNotNull(ann2);
|
||||
|
||||
testEquals(ann1, ann2, true); // this throws AnnotationFormatError
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// AnnotationWithoutAnnotationAccessModifier...
|
||||
|
||||
/*
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public interface AnnotationWithoutAnnotationAccessModifier extends Annotation {
|
||||
int m() default 1;
|
||||
}
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithoutAnnotationAccessModifier
|
||||
static class HolderX {
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void holderX_annotationWithoutAnnotationAccessModifier() {
|
||||
testGetAnnotation(HolderX.class, AnnotationWithoutAnnotationAccessModifier.class, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderX_goodAnnotation() {
|
||||
testGetAnnotation(HolderX.class, GoodAnnotation.class, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void holderX_annotations() {
|
||||
testGetAnnotations(HolderX.class, GoodAnnotation.class);
|
||||
}
|
||||
|
||||
//=======================================================
|
||||
// utils
|
||||
//
|
||||
|
||||
private static void testGetAnnotation(Class<?> holderClass,
|
||||
Class<? extends Annotation> annType,
|
||||
boolean expectedPresent) {
|
||||
Object result = null;
|
||||
try {
|
||||
try {
|
||||
result = holderClass.getAnnotation(annType);
|
||||
if (expectedPresent != (result != null)) {
|
||||
throw new AssertionError("Expected " +
|
||||
(expectedPresent ? "non-null" : "null") +
|
||||
" result, but got: " + result);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
result = t;
|
||||
throw t;
|
||||
}
|
||||
} finally {
|
||||
System.out.println("\n" +
|
||||
holderClass.getSimpleName() +
|
||||
".class.getAnnotation(" +
|
||||
annType.getSimpleName() +
|
||||
".class) = " +
|
||||
result);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testGetAnnotations(Class<?> holderClass,
|
||||
Class<? extends Annotation> ... expectedTypes) {
|
||||
Object result = null;
|
||||
try {
|
||||
try {
|
||||
Annotation[] anns = holderClass.getAnnotations();
|
||||
|
||||
Set<Class<? extends Annotation>> gotTypes =
|
||||
Stream.of(anns)
|
||||
.map(Annotation::annotationType)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Set<Class<? extends Annotation>> expTypes =
|
||||
Stream.of(expectedTypes)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (!expTypes.equals(gotTypes)) {
|
||||
throw new AssertionError("Expected annotation types: " + expTypes +
|
||||
" but got: " + Arrays.toString(anns));
|
||||
}
|
||||
result = Arrays.toString(anns);
|
||||
} catch (Throwable t) {
|
||||
result = t;
|
||||
throw t;
|
||||
}
|
||||
} finally {
|
||||
System.out.println("\n" +
|
||||
holderClass.getSimpleName() +
|
||||
".class.getAnnotations() = " +
|
||||
result);
|
||||
}
|
||||
}
|
||||
|
||||
private static void testEquals(Annotation ann1, Annotation ann2, boolean expectedEquals) {
|
||||
Object result = null;
|
||||
try {
|
||||
try {
|
||||
boolean gotEquals = ann1.equals(ann2);
|
||||
Assert.assertEquals(gotEquals, expectedEquals);
|
||||
result = gotEquals;
|
||||
} catch (Throwable t) {
|
||||
result = t;
|
||||
throw t;
|
||||
}
|
||||
} finally {
|
||||
System.out.println("\n" + ann1 + ".equals(" + ann2 + ") = " + result);
|
||||
}
|
||||
}
|
||||
}
|
||||
75
test/jdk/java/lang/annotation/AnnotationWithLambda.java
Normal file
75
test/jdk/java/lang/annotation/AnnotationWithLambda.java
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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 8147585
|
||||
* @summary Check Annotation with Lambda, with or without parameter
|
||||
* @run testng AnnotationWithLambda
|
||||
*/
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.testng.annotations.*;
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class AnnotationWithLambda {
|
||||
|
||||
@Test
|
||||
public void testAnnotationWithLambda() {
|
||||
Method[] methods = AnnotationWithLambda.MethodsWithAnnotations.class.getDeclaredMethods();
|
||||
for (Method method : methods) {
|
||||
assertTrue((method.isAnnotationPresent(LambdaWithParameter.class)) &&
|
||||
(method.isAnnotationPresent(LambdaWithoutParameter.class)));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static class MethodsWithAnnotations {
|
||||
|
||||
@LambdaWithParameter
|
||||
@LambdaWithoutParameter
|
||||
public void testAnnotationLambda() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Target(value = ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface LambdaWithParameter {
|
||||
Consumer<Integer> f1 = a -> {
|
||||
System.out.println("lambda has parameter");
|
||||
};
|
||||
}
|
||||
|
||||
@Target(value = ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface LambdaWithoutParameter {
|
||||
Runnable r = () -> System.out.println("lambda without parameter");
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8011940
|
||||
* @summary Test inheritance, order and class redefinition behaviour of RUNTIME
|
||||
* class annotations
|
||||
* @author plevart
|
||||
* @modules java.base/java.lang:open
|
||||
* java.base/sun.reflect.annotation
|
||||
*/
|
||||
|
||||
import sun.reflect.annotation.AnnotationParser;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class AnnotationsInheritanceOrderRedefinitionTest {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Ann1 {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Ann2 {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@interface Ann3 {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Ann1("A")
|
||||
@Ann2("A")
|
||||
static class A {}
|
||||
|
||||
@Ann3("B")
|
||||
static class B extends A {}
|
||||
|
||||
@Ann1("C")
|
||||
@Ann3("C")
|
||||
static class C extends B {}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
StringBuilder msgs = new StringBuilder();
|
||||
boolean ok = true;
|
||||
|
||||
ok &= annotationsEqual(msgs, A.class, true,
|
||||
ann(Ann1.class, "A"), ann(Ann2.class, "A"));
|
||||
ok &= annotationsEqual(msgs, A.class, false,
|
||||
ann(Ann1.class, "A"), ann(Ann2.class, "A"));
|
||||
ok &= annotationsEqual(msgs, B.class, true,
|
||||
ann(Ann3.class, "B"));
|
||||
ok &= annotationsEqual(msgs, B.class, false,
|
||||
ann(Ann1.class, "A"), ann(Ann2.class, "A"), ann(Ann3.class, "B"));
|
||||
ok &= annotationsEqual(msgs, C.class, true,
|
||||
ann(Ann1.class, "C"), ann(Ann3.class, "C"));
|
||||
ok &= annotationsEqual(msgs, C.class, false,
|
||||
ann(Ann1.class, "C"), ann(Ann2.class, "A"), ann(Ann3.class, "C"));
|
||||
|
||||
Annotation[] declaredAnnotatiosA = A.class.getDeclaredAnnotations();
|
||||
Annotation[] annotationsA = A.class.getAnnotations();
|
||||
Annotation[] declaredAnnotatiosB = B.class.getDeclaredAnnotations();
|
||||
Annotation[] annotationsB = B.class.getAnnotations();
|
||||
Annotation[] declaredAnnotatiosC = C.class.getDeclaredAnnotations();
|
||||
Annotation[] annotationsC = C.class.getAnnotations();
|
||||
|
||||
incrementClassRedefinedCount(A.class);
|
||||
incrementClassRedefinedCount(B.class);
|
||||
incrementClassRedefinedCount(C.class);
|
||||
|
||||
ok &= annotationsEqualButNotSame(msgs, A.class, true, declaredAnnotatiosA);
|
||||
ok &= annotationsEqualButNotSame(msgs, A.class, false, annotationsA);
|
||||
ok &= annotationsEqualButNotSame(msgs, B.class, true, declaredAnnotatiosB);
|
||||
ok &= annotationsEqualButNotSame(msgs, B.class, false, annotationsB);
|
||||
ok &= annotationsEqualButNotSame(msgs, C.class, true, declaredAnnotatiosC);
|
||||
ok &= annotationsEqualButNotSame(msgs, C.class, false, annotationsC);
|
||||
|
||||
if (!ok) {
|
||||
throw new RuntimeException("test failure\n" + msgs);
|
||||
}
|
||||
}
|
||||
|
||||
// utility methods
|
||||
|
||||
private static boolean annotationsEqualButNotSame(StringBuilder msgs,
|
||||
Class<?> declaringClass, boolean declaredOnly, Annotation[] oldAnns) {
|
||||
if (!annotationsEqual(msgs, declaringClass, declaredOnly, oldAnns)) {
|
||||
return false;
|
||||
}
|
||||
Annotation[] anns = declaredOnly
|
||||
? declaringClass.getDeclaredAnnotations()
|
||||
: declaringClass.getAnnotations();
|
||||
List<Annotation> sameAnns = new ArrayList<>();
|
||||
for (int i = 0; i < anns.length; i++) {
|
||||
if (anns[i] == oldAnns[i]) {
|
||||
sameAnns.add(anns[i]);
|
||||
}
|
||||
}
|
||||
if (!sameAnns.isEmpty()) {
|
||||
msgs.append(declaredOnly ? "declared " : "").append("annotations for ")
|
||||
.append(declaringClass.getSimpleName())
|
||||
.append(" not re-parsed after class redefinition: ")
|
||||
.append(toSimpleString(sameAnns)).append("\n");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean annotationsEqual(StringBuilder msgs,
|
||||
Class<?> declaringClass, boolean declaredOnly, Annotation... expectedAnns) {
|
||||
Annotation[] anns = declaredOnly
|
||||
? declaringClass.getDeclaredAnnotations()
|
||||
: declaringClass.getAnnotations();
|
||||
if (!Arrays.equals(anns, expectedAnns)) {
|
||||
msgs.append(declaredOnly ? "declared " : "").append("annotations for ")
|
||||
.append(declaringClass.getSimpleName()).append(" are: ")
|
||||
.append(toSimpleString(anns)).append(", expected: ")
|
||||
.append(toSimpleString(expectedAnns)).append("\n");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static Annotation ann(Class<? extends Annotation> annotationType,
|
||||
Object value) {
|
||||
return AnnotationParser.annotationForMap(annotationType,
|
||||
Collections.singletonMap("value", value));
|
||||
}
|
||||
|
||||
private static String toSimpleString(List<Annotation> anns) {
|
||||
return toSimpleString(anns.toArray(new Annotation[anns.size()]));
|
||||
}
|
||||
|
||||
private static String toSimpleString(Annotation[] anns) {
|
||||
StringJoiner joiner = new StringJoiner(", ");
|
||||
for (Annotation ann : anns) {
|
||||
joiner.add(toSimpleString(ann));
|
||||
}
|
||||
return joiner.toString();
|
||||
}
|
||||
|
||||
private static String toSimpleString(Annotation ann) {
|
||||
Class<? extends Annotation> annotationType = ann.annotationType();
|
||||
Object value;
|
||||
try {
|
||||
value = annotationType.getDeclaredMethod("value").invoke(ann);
|
||||
} catch (IllegalAccessException | InvocationTargetException
|
||||
| NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return "@" + annotationType.getSimpleName() + "(" + value + ")";
|
||||
}
|
||||
|
||||
private static final Field classRedefinedCountField;
|
||||
|
||||
static {
|
||||
try {
|
||||
classRedefinedCountField = Class.class.getDeclaredField("classRedefinedCount");
|
||||
classRedefinedCountField.setAccessible(true);
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void incrementClassRedefinedCount(Class<?> clazz) {
|
||||
try {
|
||||
classRedefinedCountField.set(clazz,
|
||||
((Integer) classRedefinedCountField.get(clazz)) + 1);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
285
test/jdk/java/lang/annotation/ClassFileGenerator.java
Normal file
285
test/jdk/java/lang/annotation/ClassFileGenerator.java
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2024, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Create class file using Class-File API, slightly modified the ASMifier output
|
||||
*/
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.classfile.Annotation;
|
||||
import java.lang.classfile.AnnotationElement;
|
||||
import java.lang.classfile.AnnotationValue;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.AnnotationDefaultAttribute;
|
||||
import java.lang.classfile.attribute.ExceptionsAttribute;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
|
||||
import static java.lang.classfile.ClassFile.ACC_ABSTRACT;
|
||||
import static java.lang.classfile.ClassFile.ACC_PUBLIC;
|
||||
import static java.lang.constant.ConstantDescs.CD_Exception;
|
||||
import static java.lang.constant.ConstantDescs.CD_Object;
|
||||
import static java.lang.constant.ConstantDescs.CD_int;
|
||||
import static java.lang.constant.ConstantDescs.MTD_void;
|
||||
import static java.lang.reflect.AccessFlag.ABSTRACT;
|
||||
import static java.lang.reflect.AccessFlag.INTERFACE;
|
||||
import static java.lang.reflect.AccessFlag.PUBLIC;
|
||||
|
||||
public class ClassFileGenerator {
|
||||
private static final ClassDesc CD_Annotation = java.lang.annotation.Annotation.class.describeConstable().orElseThrow();
|
||||
private static final ClassDesc CD_Retention = Retention.class.describeConstable().orElseThrow();
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
classFileWriter("AnnotationWithVoidReturn.class", AnnotationWithVoidReturnDump.dump());
|
||||
classFileWriter("AnnotationWithParameter.class", AnnotationWithParameterDump.dump());
|
||||
classFileWriter("AnnotationWithExtraInterface.class", AnnotationWithExtraInterfaceDump.dump());
|
||||
classFileWriter("AnnotationWithException.class", AnnotationWithExceptionDump.dump());
|
||||
classFileWriter("AnnotationWithHashCode.class", AnnotationWithHashCodeDump.dump());
|
||||
classFileWriter("AnnotationWithDefaultMember.class", AnnotationWithDefaultMemberDump.dump());
|
||||
classFileWriter("AnnotationWithoutAnnotationAccessModifier.class",
|
||||
AnnotationWithoutAnnotationAccessModifierDump.dump());
|
||||
classFileWriter("HolderX.class", HolderXDump.dump());
|
||||
}
|
||||
|
||||
private static void classFileWriter(String name, byte[] contents) throws IOException {
|
||||
try (FileOutputStream fos = new FileOutputStream(new File(System.getProperty("test.classes"),
|
||||
name))) {
|
||||
fos.write(contents);
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithVoidReturn {
|
||||
void m() default 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithVoidReturnDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithVoidReturn"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation);
|
||||
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("m", MTD_void, ACC_PUBLIC | ACC_ABSTRACT,
|
||||
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithParameter {
|
||||
int m(int x) default -1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithParameterDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithParameter"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation);
|
||||
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("m", MethodTypeDesc.of(CD_int, CD_int), ACC_PUBLIC | ACC_ABSTRACT,
|
||||
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(-1))));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithExtraInterface extends java.io.Serializable {
|
||||
int m() default 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithExtraInterfaceDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithExtraInterface"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation, Serializable.class.describeConstable().orElseThrow());
|
||||
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
|
||||
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithException {
|
||||
int m() throws Exception default 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithExceptionDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithException"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation);
|
||||
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT, mb -> {
|
||||
mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1)));
|
||||
mb.with(ExceptionsAttribute.ofSymbols(CD_Exception));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithHashCode {
|
||||
int hashCode() default 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithHashCodeDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithHashCode"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation);
|
||||
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("hashCode", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
|
||||
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithDefaultMember {
|
||||
int m() default 1;
|
||||
default int d() default 2 { return 2; }
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithDefaultMemberDump {
|
||||
public static byte[] dump() throws Exception {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithDefaultMember"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation);
|
||||
clb.withFlags(PUBLIC, AccessFlag.ANNOTATION, ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
|
||||
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
|
||||
clb.withMethod("d", MethodTypeDesc.of(CD_int), ACC_PUBLIC, mb -> {
|
||||
mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(2)));
|
||||
mb.withCode(cob -> {
|
||||
cob.iconst_2();
|
||||
cob.ireturn();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public interface AnnotationWithoutAnnotationAccessModifier extends java.lang.annotation.Annotation {
|
||||
int m() default 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnotationWithoutAnnotationAccessModifierDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("AnnotationWithoutAnnotationAccessModifier"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withInterfaceSymbols(CD_Annotation);
|
||||
clb.withFlags(PUBLIC, /*AccessFlag.ANNOTATION,*/ ABSTRACT, AccessFlag.INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(CD_Retention, AnnotationElement.of("value",
|
||||
AnnotationValue.of(RetentionPolicy.RUNTIME)))
|
||||
));
|
||||
clb.withMethod("m", MethodTypeDesc.of(CD_int), ACC_PUBLIC | ACC_ABSTRACT,
|
||||
mb -> mb.with(AnnotationDefaultAttribute.of(AnnotationValue.ofInt(1))));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac
|
||||
since AnnotationWithoutAnnotationAccessModifier is not marked with ACC_ANNOTATION:
|
||||
|
||||
@GoodAnnotation
|
||||
@AnnotationWithoutAnnotationAccessModifier
|
||||
public interface HolderX {
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class HolderXDump {
|
||||
public static byte[] dump() {
|
||||
return ClassFile.of().build(ClassDesc.of("HolderX"), clb -> {
|
||||
clb.withSuperclass(CD_Object);
|
||||
clb.withFlags(PUBLIC, ABSTRACT, INTERFACE);
|
||||
clb.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(ClassDesc.of("GoodAnnotation")),
|
||||
Annotation.of(ClassDesc.of("ClassFileGenerator$AnnotationWithoutAnnotationAccessModifier"))
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
141
test/jdk/java/lang/annotation/DuplicateAnnotationsTest.java
Normal file
141
test/jdk/java/lang/annotation/DuplicateAnnotationsTest.java
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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 8345614 8350704
|
||||
* @summary Ensure behavior with duplicated annotations - class, method, or
|
||||
* field fails fast on duplicate annotations, but parameter allows them
|
||||
* @library /test/lib
|
||||
* @run junit DuplicateAnnotationsTest
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.AnnotationFormatError;
|
||||
import java.lang.classfile.*;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleParameterAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.test.lib.ByteCodeLoader;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class DuplicateAnnotationsTest {
|
||||
static ClassModel cm;
|
||||
|
||||
@BeforeAll
|
||||
static void setup() throws IOException {
|
||||
Path annoDuplicatedClass = Path.of(System.getProperty("test.classes")).resolve("AnnotationDuplicated.class");
|
||||
cm = ClassFile.of().parse(annoDuplicatedClass);
|
||||
}
|
||||
|
||||
interface Extractor {
|
||||
AnnotatedElement find(Class<?> cl) throws ReflectiveOperationException;
|
||||
}
|
||||
|
||||
// Compiler hint
|
||||
static Extractor extract(Extractor e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
static Arguments[] arguments() {
|
||||
Annotation annotationOne = Annotation.of(ClassDesc.of("java.lang.Deprecated"), AnnotationElement.ofBoolean("forRemoval", true));
|
||||
Annotation annotationTwo = Annotation.of(ClassDesc.of("java.lang.Deprecated"), AnnotationElement.ofString("since", "24"));
|
||||
RuntimeVisibleAnnotationsAttribute rvaa = RuntimeVisibleAnnotationsAttribute.of(
|
||||
List.of(annotationOne, annotationTwo)
|
||||
);
|
||||
|
||||
return new Arguments[]{
|
||||
Arguments.of(
|
||||
"class", true,
|
||||
ClassTransform.endHandler(cob -> cob.with(rvaa)),
|
||||
extract(c -> c)
|
||||
),
|
||||
Arguments.of(
|
||||
"field", true,
|
||||
ClassTransform.transformingFields(FieldTransform.endHandler(fb -> fb.with(rvaa))),
|
||||
extract(c -> c.getDeclaredField("field"))
|
||||
),
|
||||
Arguments.of(
|
||||
"method", true,
|
||||
ClassTransform.transformingMethods(MethodTransform.endHandler(mb -> mb.with(rvaa))),
|
||||
extract(c -> c.getDeclaredConstructor(int.class))
|
||||
),
|
||||
Arguments.of(
|
||||
"parameter", false, // Surprisingly, parameters always allowed duplicate annotations
|
||||
ClassTransform.transformingMethods(MethodTransform.endHandler(mb -> mb.with(
|
||||
RuntimeVisibleParameterAnnotationsAttribute.of(
|
||||
List.of(List.of(annotationOne, annotationTwo))
|
||||
)
|
||||
))),
|
||||
extract(c -> c.getDeclaredConstructor(int.class).getParameters()[0])
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A test case represents a declaration that can be annotated.
|
||||
* Different declarations have different behaviors when multiple annotations
|
||||
* of the same interface are present (without a container annotation).
|
||||
*
|
||||
* @param caseName the type of declaration, for pretty printing in JUnit
|
||||
* @param fails whether this case should fail upon encountering duplicate annotations
|
||||
* @param ct transform to install duplicate annotations on the specific declaration
|
||||
* @param extractor function to access the AnnotatedElement representing that declaration
|
||||
*/
|
||||
@MethodSource("arguments")
|
||||
@ParameterizedTest
|
||||
void test(String caseName, boolean fails, ClassTransform ct, Extractor extractor) throws IOException, ReflectiveOperationException {
|
||||
var clazz = ByteCodeLoader.load("AnnotationDuplicated", ClassFile.of().transformClass(cm, ct));
|
||||
var element = assertDoesNotThrow(() -> extractor.find(clazz));
|
||||
Executable exec = () -> element.getAnnotation(Deprecated.class);
|
||||
if (fails) {
|
||||
var ex = assertThrows(AnnotationFormatError.class, exec, "no duplicate annotation access");
|
||||
assertTrue(ex.getMessage().contains("Deprecated"), () -> "missing problematic annotation: " + ex.getMessage());
|
||||
assertTrue(ex.getMessage().contains("AnnotationDuplicated"), () -> "missing container class: " + ex.getMessage());
|
||||
} else {
|
||||
assertDoesNotThrow(exec, "obtaining duplicate annotations should be fine");
|
||||
assertEquals(2, Arrays.stream(element.getAnnotations())
|
||||
.filter(anno -> anno instanceof Deprecated)
|
||||
.count());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate annotations on class, field, method (constructor), method parameter
|
||||
class AnnotationDuplicated {
|
||||
int field;
|
||||
|
||||
AnnotationDuplicated(int arg) {
|
||||
}
|
||||
}
|
||||
57
test/jdk/java/lang/annotation/EnumConstructorAnnotation.java
Normal file
57
test/jdk/java/lang/annotation/EnumConstructorAnnotation.java
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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 8263763
|
||||
* @summary Check that annotations on an enum constructor are indexed correctly.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class EnumConstructorAnnotation {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Constructor<?> c = SampleEnum.class.getDeclaredConstructors()[0];
|
||||
Annotation[] a1 = c.getParameters()[2].getAnnotations(), a2 = c.getParameterAnnotations()[2];
|
||||
for (Annotation[] a : Arrays.asList(a1, a2)) {
|
||||
if (a.length != 1) {
|
||||
throw new RuntimeException("Unexpected length " + a.length);
|
||||
} else if (a[0].annotationType() != SampleAnnotation.class) {
|
||||
throw new RuntimeException("Unexpected type " + a[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum SampleEnum {
|
||||
INSTANCE("foo");
|
||||
SampleEnum(@SampleAnnotation String value) { }
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface SampleAnnotation { }
|
||||
}
|
||||
65
test/jdk/java/lang/annotation/EqualityTest.java
Normal file
65
test/jdk/java/lang/annotation/EqualityTest.java
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 2021, 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 8071859 8169629
|
||||
* @summary Check annotation equality behavior against the invocation handler
|
||||
* @compile --release 8 EqualityTest.java
|
||||
* @run main EqualityTest
|
||||
* @compile EqualityTest.java
|
||||
* @run main EqualityTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
@TestAnnotation
|
||||
public class EqualityTest {
|
||||
public static void main(String... args) throws Exception {
|
||||
TestAnnotation annotation =
|
||||
EqualityTest.class.getAnnotation(TestAnnotation.class);
|
||||
InvocationHandler handler = Proxy.getInvocationHandler(annotation);
|
||||
|
||||
testEquality(annotation, handler, false);
|
||||
testEquality(annotation, annotation, true);
|
||||
testEquality(handler, handler, true);
|
||||
testEquality(annotation, AnnotationHost.class.getAnnotation(TestAnnotation.class), true);
|
||||
}
|
||||
|
||||
private static void testEquality(Object a, Object b, boolean expected) {
|
||||
boolean result = a.equals(b);
|
||||
if (result != b.equals(a) || result != expected)
|
||||
throw new RuntimeException("Unexpected result");
|
||||
}
|
||||
|
||||
@TestAnnotation
|
||||
private static class AnnotationHost {}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TestAnnotation {
|
||||
// Trigger creation of synthetic method to initialize r.
|
||||
public static final Runnable r = () -> {};
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
@DangerousAnnotation(utopia=Utopia.BRIGADOON,
|
||||
thirtyTwoBitsAreNotEnough=42,
|
||||
classy=Fleeting.class,
|
||||
classies={Object.class, int.class},
|
||||
moreClassies={})
|
||||
public class AnnotationHost {}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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 5040830
|
||||
* @summary Verify information annotation strings with exception proxies
|
||||
* @compile -sourcepath version1 version1/Fleeting.java version1/Utopia.java version1/DangerousAnnotation.java
|
||||
* @compile AnnotationHost.java
|
||||
* @build ExceptionalToStringTest
|
||||
* @run main ExceptionalToStringTest
|
||||
* @clean Utopia DangerousAnnotation
|
||||
* @compile -sourcepath version2 -implicit:none version2/Utopia.java
|
||||
* @compile -sourcepath version2 -implicit:none version2/DangerousAnnotation.java
|
||||
* @clean Fleeting
|
||||
* @run main ExceptionalToStringTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* There are three potential exception conditions which can occur
|
||||
* reading annotations:
|
||||
*
|
||||
* EnumConstantNotPresentException - "Thrown when an application tries
|
||||
* to access an enum constant by name and the enum type contains no
|
||||
* constant with the specified name."
|
||||
*
|
||||
* AnnotationTypeMismatchException - "Thrown to indicate that a
|
||||
* program has attempted to access an element of an annotation whose
|
||||
* type has changed after the annotation was compiled (or serialized)"
|
||||
*
|
||||
* TypeNotPresentException - "Thrown when an application tries to
|
||||
* access a type using a string representing the type's name, but no
|
||||
* definition for the type with the specified name can be found."
|
||||
*
|
||||
* The test reads an annotation, DangerousAnnotation, which can
|
||||
* display all three pathologies. The pathologies are <em>not</em>
|
||||
* present when the version1 sources are used but are present with the
|
||||
* version2 sources. The version2 sources remove an enum constant
|
||||
* (EnumConstantNotPresentException), change the return type of an
|
||||
* annotation method (AnnotationTypeMismatchException), and remove a
|
||||
* type whose Class literal is referenced (TypeNotPresentException).
|
||||
*/
|
||||
public class ExceptionalToStringTest {
|
||||
public static void main(String... args) {
|
||||
String annotationAsString = AnnotationHost.class.getAnnotation(DangerousAnnotation.class).toString();
|
||||
|
||||
// Verify no occurrence of "ExceptionProxy" in the string.
|
||||
if (annotationAsString.indexOf("ExceptionProxy") != -1) {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DangerousAnnotation {
|
||||
Utopia utopia();
|
||||
int thirtyTwoBitsAreNotEnough();
|
||||
Class<?> classy();
|
||||
Class<?>[] classies();
|
||||
Class<?>[] moreClassies();
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Fleeting {
|
||||
int value();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
public enum Utopia {
|
||||
SHANGRI_LA,
|
||||
BRIGADOON; // Only there one day out of every 100 years.
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface DangerousAnnotation {
|
||||
Utopia utopia();
|
||||
long thirtyTwoBitsAreNotEnough();
|
||||
Class<?> classy();
|
||||
Class<?>[] classies();
|
||||
Class<?>[] moreClassies();
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
public enum Utopia {
|
||||
SHANGRI_LA;
|
||||
//BRIGADOON -- Only there one day out of every 100 years.
|
||||
}
|
||||
31
test/jdk/java/lang/annotation/GoodAnnotation.java
Normal file
31
test/jdk/java/lang/annotation/GoodAnnotation.java
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* Simple conforming runtime annotation.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface GoodAnnotation {}
|
||||
135
test/jdk/java/lang/annotation/LoaderLeakTest.java
Normal file
135
test/jdk/java/lang/annotation/LoaderLeakTest.java
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2025, 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 5040740
|
||||
* @summary annotations cause memory leak
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.process.*
|
||||
* @run testng/timeout=480 LoaderLeakTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
import java.io.FileInputStream;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
public class LoaderLeakTest {
|
||||
|
||||
@Test
|
||||
public void testWithoutReadingAnnotations() throws Throwable {
|
||||
runJavaProcessExpectSuccessExitCode("Main");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithReadingAnnotations() throws Throwable {
|
||||
runJavaProcessExpectSuccessExitCode("Main", "foo");
|
||||
}
|
||||
|
||||
private void runJavaProcessExpectSuccessExitCode(String ... command) throws Throwable {
|
||||
var processBuilder = ProcessTools.createTestJavaProcessBuilder(command)
|
||||
.directory(Paths.get(Utils.TEST_CLASSES).toFile());
|
||||
ProcessTools.executeCommand(processBuilder).shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Main {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
doTest(args.length != 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void doTest(boolean readAnn) throws Exception {
|
||||
ClassLoader loader = new SimpleClassLoader();
|
||||
var c = new WeakReference<Class<?>>(loader.loadClass("C"));
|
||||
if (c.refersTo(null)) throw new AssertionError("class missing after loadClass");
|
||||
// c.get() should never return null here since we hold a strong
|
||||
// reference to the class loader that loaded the class referred by c.
|
||||
if (c.get().getClassLoader() != loader) throw new AssertionError("wrong classloader");
|
||||
if (readAnn) System.out.println(c.get().getAnnotations()[0]);
|
||||
if (c.refersTo(null)) throw new AssertionError("class missing before GC");
|
||||
System.gc();
|
||||
System.gc();
|
||||
if (c.refersTo(null)) throw new AssertionError("class missing after GC but before loader is unreachable");
|
||||
System.gc();
|
||||
System.gc();
|
||||
Reference.reachabilityFence(loader);
|
||||
loader = null;
|
||||
|
||||
// Might require multiple calls to System.gc() for weak-references
|
||||
// processing to be complete. If the weak-reference is not cleared as
|
||||
// expected we will hang here until timed out by the test harness.
|
||||
while (true) {
|
||||
System.gc();
|
||||
Thread.sleep(20);
|
||||
if (c.refersTo(null)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@interface A {
|
||||
B b();
|
||||
}
|
||||
|
||||
@interface B { }
|
||||
|
||||
@A(b=@B()) class C { }
|
||||
|
||||
class SimpleClassLoader extends ClassLoader {
|
||||
public SimpleClassLoader() { }
|
||||
|
||||
private byte[] getClassImplFromDataBase(String className) {
|
||||
try {
|
||||
return Files.readAllBytes(Paths.get(className + ".class"));
|
||||
} catch (Exception e) {
|
||||
throw new Error("could not load class " + className, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> loadClass(String className, boolean resolveIt)
|
||||
throws ClassNotFoundException {
|
||||
switch (className) {
|
||||
case "A", "B", "C" -> {
|
||||
var classData = getClassImplFromDataBase(className);
|
||||
return defineClass(className, classData, 0, classData.length);
|
||||
}
|
||||
}
|
||||
return super.loadClass(className, resolveIt);
|
||||
}
|
||||
|
||||
}
|
||||
118
test/jdk/java/lang/annotation/MalformedAnnotationTest.java
Normal file
118
test/jdk/java/lang/annotation/MalformedAnnotationTest.java
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
/*
|
||||
* Copyright (c) 2024, 2025, 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 8350704
|
||||
* @summary Test behaviors with malformed annotations (in class files)
|
||||
* @library /test/lib
|
||||
* @run junit MalformedAnnotationTest
|
||||
*/
|
||||
|
||||
import jdk.test.lib.ByteCodeLoader;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.classfile.Annotation;
|
||||
import java.lang.classfile.AnnotationElement;
|
||||
import java.lang.classfile.AnnotationValue;
|
||||
import java.lang.classfile.ClassFile;
|
||||
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.reflect.GenericSignatureFormatError;
|
||||
import java.util.Arrays;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class MalformedAnnotationTest {
|
||||
|
||||
/**
|
||||
* An annotation that has elements of the Class type.
|
||||
* Useful for checking behavior when the string is not a descriptor string.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ClassCarrier {
|
||||
Class<?> value();
|
||||
}
|
||||
|
||||
static Stream<String> badFieldDescriptors() {
|
||||
return Arrays.stream(new String[] {
|
||||
"Not a_descriptor",
|
||||
"()V",
|
||||
"Ljava/lang/Object",
|
||||
"Ljava/",
|
||||
"Ljava/util/Map.Entry;",
|
||||
"[".repeat(256) + "I",
|
||||
"Lbad.Name;",
|
||||
"Lbad[Name;",
|
||||
"L;",
|
||||
"L/Missing;",
|
||||
"Lmissing/;",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures bad class descriptors in annotations lead to
|
||||
* {@link GenericSignatureFormatError} and the error message contains the
|
||||
* malformed descriptor string.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("badFieldDescriptors")
|
||||
void testMalformedClassValue(String badDescString) throws Exception {
|
||||
var cl = spinClass(badDescString);
|
||||
var ex = assertThrows(GenericSignatureFormatError.class, () -> cl.getDeclaredAnnotation(ClassCarrier.class));
|
||||
assertTrue(ex.getMessage().contains(badDescString), () -> "Uninformative error: " + ex);
|
||||
}
|
||||
|
||||
private static Class<?> spinClass(String desc) throws Exception {
|
||||
var bytes = ClassFile.of().build(ClassDesc.of("Test"), clb -> clb
|
||||
.with(RuntimeVisibleAnnotationsAttribute.of(
|
||||
Annotation.of(ClassCarrier.class.describeConstable().orElseThrow(),
|
||||
AnnotationElement.of("value", AnnotationValue.ofClass(clb
|
||||
.constantPool().utf8Entry(desc))))
|
||||
)));
|
||||
return new ByteCodeLoader("Test", bytes, ClassCarrier.class.getClassLoader()).loadClass("Test");
|
||||
}
|
||||
|
||||
static Stream<String> goodFieldDescriptors() {
|
||||
return Arrays.stream(new String[] {
|
||||
"Ljava/lang/Object<*>;", // previously MalformedParameterizedTypeException
|
||||
"[Ljava/util/Optional<*>;", // previously ClassCastException
|
||||
"Ljava/util/Map$Entry<**>;", // previously ClassCastException
|
||||
});
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("goodFieldDescriptors")
|
||||
void testLegalClassValue(String goodDescString) throws Exception {
|
||||
var cl = spinClass(goodDescString);
|
||||
var anno = cl.getDeclaredAnnotation(ClassCarrier.class);
|
||||
assertThrows(TypeNotPresentException.class, anno::value);
|
||||
}
|
||||
}
|
||||
30
test/jdk/java/lang/annotation/Missing/A.java
Normal file
30
test/jdk/java/lang/annotation/Missing/A.java
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to have a missing annotation applied for running MissingTest.
|
||||
*/
|
||||
@Missing
|
||||
@Marker
|
||||
public class A {
|
||||
}
|
||||
31
test/jdk/java/lang/annotation/Missing/B.java
Normal file
31
test/jdk/java/lang/annotation/Missing/B.java
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to have an indirectly missing annotation applied for
|
||||
* running MisssingTest.
|
||||
*/
|
||||
@MissingWrapper(@Missing)
|
||||
@Marker
|
||||
public class B {
|
||||
}
|
||||
31
test/jdk/java/lang/annotation/Missing/C.java
Normal file
31
test/jdk/java/lang/annotation/Missing/C.java
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to have a missing annotation applied for running MissingTest.
|
||||
*/
|
||||
public class C {
|
||||
public void method1(@Missing @Marker Object param1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
31
test/jdk/java/lang/annotation/Missing/D.java
Normal file
31
test/jdk/java/lang/annotation/Missing/D.java
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class to have a missing annotation applied for running MissingTest.
|
||||
*/
|
||||
public class D {
|
||||
public void method1(@MissingWrapper(@Missing) @Marker Object param1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
32
test/jdk/java/lang/annotation/Missing/Marker.java
Normal file
32
test/jdk/java/lang/annotation/Missing/Marker.java
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* A marker annotation. Used so that at least one annotation will be
|
||||
* present on the classes tested by MissingTest.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
public @interface Marker {}
|
||||
32
test/jdk/java/lang/annotation/Missing/Missing.java
Normal file
32
test/jdk/java/lang/annotation/Missing/Missing.java
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* The class file for this annotation type is missing when MissingTest
|
||||
* is run.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
public @interface Missing {}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The enum that will be seen at compile-time.
|
||||
*
|
||||
* <p>The filename deliberately does not match, since we need to declare two versions of the enum
|
||||
* for compile-time and runtime.
|
||||
*/
|
||||
enum Enum {
|
||||
ONE,
|
||||
TWO,
|
||||
THREE
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The enum that will be seen at runtime.
|
||||
*
|
||||
* <p>The filename deliberately does not match, since we need to declare two versions of the enum
|
||||
* for compile-time and runtime.
|
||||
*/
|
||||
enum Enum {
|
||||
ONE
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
|
||||
/** An annotation that will be missing at runtime. */
|
||||
@Retention(RUNTIME)
|
||||
public @interface MissingAnnotation {}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7183985
|
||||
* @summary getAnnotation() should throw NoClassDefFoundError when an annotation class is not
|
||||
* present at runtime
|
||||
* @compile MissingAnnotationArrayElementTest.java MissingAnnotation.java
|
||||
* @clean MissingAnnotation
|
||||
* @run main MissingAnnotationArrayElementTest
|
||||
*/
|
||||
public class MissingAnnotationArrayElementTest {
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@interface AnnotationAnnotation {
|
||||
MissingAnnotation[] value();
|
||||
}
|
||||
|
||||
@AnnotationAnnotation({@MissingAnnotation, @MissingAnnotation})
|
||||
static class Test {
|
||||
void f(@AnnotationAnnotation({@MissingAnnotation, @MissingAnnotation}) int x) {}
|
||||
|
||||
Test(@AnnotationAnnotation({@MissingAnnotation, @MissingAnnotation}) int x) {}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// MissingAnnotation will be absent from the runtime classpath, causing a
|
||||
// NoClassDefFoundError when AnnotationAnnotation is read (since the type of its value array
|
||||
// references cannot be completed).
|
||||
assertThrowsNoClassDefFoundError(
|
||||
() -> Test.class.getAnnotation(AnnotationAnnotation.class));
|
||||
Method method = Test.class.getDeclaredMethod("f", int.class);
|
||||
assertThrowsNoClassDefFoundError(method::getParameterAnnotations);
|
||||
Constructor constructor = Test.class.getDeclaredConstructor(int.class);
|
||||
assertThrowsNoClassDefFoundError(constructor::getParameterAnnotations);
|
||||
}
|
||||
|
||||
interface ThrowingRunnable {
|
||||
void run() throws Exception;
|
||||
}
|
||||
|
||||
static void assertThrowsNoClassDefFoundError(ThrowingRunnable throwingRunnable)
|
||||
throws Exception {
|
||||
try {
|
||||
throwingRunnable.run();
|
||||
throw new AssertionError("expected exception");
|
||||
} catch (NoClassDefFoundError expected) {
|
||||
if (!expected.getMessage().contains("MissingAnnotation")) {
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
/** A class that will be missing at runtime. */
|
||||
public class MissingClass {}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
/** A class that will be missing at runtime. */
|
||||
public class MissingClass2 {}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.Arrays;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7183985
|
||||
* @summary getAnnotation() throws an ArrayStoreException when the annotation class not present
|
||||
* @compile MissingClassArrayElementTest.java MissingClass.java MissingClass2.java
|
||||
* @clean MissingClass MissingClass2
|
||||
* @run main MissingClassArrayElementTest
|
||||
*/
|
||||
public class MissingClassArrayElementTest {
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@interface AnnotationAnnotation {
|
||||
ClassArrayAnnotation[] value();
|
||||
}
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@interface ClassArrayAnnotation {
|
||||
Class<?>[] value();
|
||||
}
|
||||
|
||||
@AnnotationAnnotation({
|
||||
@ClassArrayAnnotation({MissingClass.class}),
|
||||
@ClassArrayAnnotation({MissingClass.class, String.class}),
|
||||
@ClassArrayAnnotation({String.class, MissingClass.class}),
|
||||
@ClassArrayAnnotation({MissingClass.class, MissingClass2.class}),
|
||||
@ClassArrayAnnotation({String.class})
|
||||
})
|
||||
static class Test {
|
||||
void f(
|
||||
@AnnotationAnnotation({
|
||||
@ClassArrayAnnotation({MissingClass.class, MissingClass.class}),
|
||||
@ClassArrayAnnotation({Float.class})
|
||||
})
|
||||
int x,
|
||||
@AnnotationAnnotation({@ClassArrayAnnotation({Double.class})}) int y) {}
|
||||
|
||||
Test(
|
||||
@AnnotationAnnotation({
|
||||
@ClassArrayAnnotation({MissingClass.class, MissingClass.class}),
|
||||
@ClassArrayAnnotation({Short.class}),
|
||||
})
|
||||
int x,
|
||||
@AnnotationAnnotation({@ClassArrayAnnotation({Character.class})}) int y) {}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
classAnnotationTest();
|
||||
methodParameterAnnotationsTest();
|
||||
constructorParameterAnnotationsTest();
|
||||
}
|
||||
|
||||
static void classAnnotationTest() throws Exception {
|
||||
ClassArrayAnnotation[] outer = Test.class.getAnnotation(AnnotationAnnotation.class).value();
|
||||
assertMissing(outer[0]);
|
||||
assertMissing(outer[1]);
|
||||
assertMissing(outer[2]);
|
||||
assertMissing(outer[3]);
|
||||
assertArrayEquals(outer[4].value(), new Class<?>[] {String.class});
|
||||
}
|
||||
|
||||
static void methodParameterAnnotationsTest() throws Exception {
|
||||
AnnotationAnnotation[] methodParameterAnnotations =
|
||||
Arrays.stream(
|
||||
Test.class
|
||||
.getDeclaredMethod("f", int.class, int.class)
|
||||
.getParameterAnnotations())
|
||||
.map(x -> ((AnnotationAnnotation) x[0]))
|
||||
.toArray(AnnotationAnnotation[]::new);
|
||||
// The first parameter's annotation contains some well-formed values, and the second
|
||||
// parameter's
|
||||
// annotation is well-formed
|
||||
assertArrayEquals(
|
||||
methodParameterAnnotations[0].value()[1].value(), new Class<?>[] {Float.class});
|
||||
assertArrayEquals(
|
||||
methodParameterAnnotations[1].value()[0].value(), new Class<?>[] {Double.class});
|
||||
// The first parameter's annotation contains a missing value
|
||||
assertMissing(methodParameterAnnotations[0].value()[0]);
|
||||
}
|
||||
|
||||
static void constructorParameterAnnotationsTest() throws Exception {
|
||||
AnnotationAnnotation[] constructorParameterAnnotations =
|
||||
Arrays.stream(
|
||||
Test.class
|
||||
.getDeclaredConstructor(int.class, int.class)
|
||||
.getParameterAnnotations())
|
||||
.map(x -> ((AnnotationAnnotation) x[0]))
|
||||
.toArray(AnnotationAnnotation[]::new);
|
||||
// The first parameter's annotation contains some well-formed values, and the second
|
||||
// parameter's
|
||||
// annotation is well-formed
|
||||
assertArrayEquals(
|
||||
constructorParameterAnnotations[0].value()[1].value(),
|
||||
new Class<?>[] {Short.class});
|
||||
assertArrayEquals(
|
||||
constructorParameterAnnotations[1].value()[0].value(),
|
||||
new Class<?>[] {Character.class});
|
||||
// The first parameter's annotation contains a missing value
|
||||
assertMissing(constructorParameterAnnotations[0].value()[0]);
|
||||
}
|
||||
|
||||
static void assertArrayEquals(Object[] actual, Object[] expected) {
|
||||
if (!Arrays.equals(actual, expected)) {
|
||||
throw new AssertionError(
|
||||
"expected: " + Arrays.toString(expected) + ", was: " + Arrays.toString(actual));
|
||||
}
|
||||
}
|
||||
|
||||
static void assertMissing(ClassArrayAnnotation missing) {
|
||||
try {
|
||||
missing.value();
|
||||
throw new AssertionError("expected exception");
|
||||
} catch (TypeNotPresentException expected) {
|
||||
if (!expected.typeName().equals("MissingClass")) {
|
||||
throw new AssertionError(
|
||||
"expected TypeNotPresentException: MissingClass", expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google Inc. 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.
|
||||
*/
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.Arrays;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7183985
|
||||
* @summary getAnnotation() throws an ArrayStoreException when the annotation class not present
|
||||
* @compile MissingEnumArrayElementTest.java EnumToCompileAgainst.java
|
||||
* @clean Enum
|
||||
* @compile EnumToRunAgainst.java
|
||||
* @run main MissingEnumArrayElementTest
|
||||
*/
|
||||
public class MissingEnumArrayElementTest {
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@interface AnnotationAnnotation {
|
||||
EnumArrayAnnotation[] value();
|
||||
}
|
||||
|
||||
@Retention(RUNTIME)
|
||||
@interface EnumArrayAnnotation {
|
||||
Enum[] value();
|
||||
}
|
||||
|
||||
@AnnotationAnnotation({
|
||||
@EnumArrayAnnotation({Enum.TWO}),
|
||||
@EnumArrayAnnotation({Enum.ONE, Enum.TWO}),
|
||||
@EnumArrayAnnotation({Enum.TWO, Enum.ONE}),
|
||||
@EnumArrayAnnotation({Enum.TWO, Enum.THREE}),
|
||||
@EnumArrayAnnotation({Enum.ONE}),
|
||||
})
|
||||
static class Test {
|
||||
void f(
|
||||
@AnnotationAnnotation({
|
||||
@EnumArrayAnnotation({Enum.TWO, Enum.ONE}),
|
||||
@EnumArrayAnnotation({Enum.ONE})
|
||||
})
|
||||
int x,
|
||||
@AnnotationAnnotation({@EnumArrayAnnotation({Enum.ONE})}) int y) {}
|
||||
|
||||
Test(
|
||||
@AnnotationAnnotation({
|
||||
@EnumArrayAnnotation({Enum.TWO, Enum.ONE}),
|
||||
@EnumArrayAnnotation({Enum.ONE})
|
||||
})
|
||||
int x,
|
||||
@AnnotationAnnotation({@EnumArrayAnnotation({Enum.ONE})}) int y) {}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
classAnnotationTest();
|
||||
methodParameterAnnotationsTest();
|
||||
constructorParameterAnnotationsTest();
|
||||
}
|
||||
|
||||
static void classAnnotationTest() throws Exception {
|
||||
EnumArrayAnnotation[] outer = Test.class.getAnnotation(AnnotationAnnotation.class).value();
|
||||
assertMissing(outer[0]);
|
||||
assertMissing(outer[1]);
|
||||
assertMissing(outer[2]);
|
||||
assertMissing(outer[3]);
|
||||
assertArrayEquals(outer[4].value(), new Enum[] {Enum.ONE});
|
||||
}
|
||||
|
||||
static void methodParameterAnnotationsTest() throws Exception {
|
||||
AnnotationAnnotation[] methodParameterAnnotations =
|
||||
Arrays.stream(
|
||||
Test.class
|
||||
.getDeclaredMethod("f", int.class, int.class)
|
||||
.getParameterAnnotations())
|
||||
.map(x -> ((AnnotationAnnotation) x[0]))
|
||||
.toArray(AnnotationAnnotation[]::new);
|
||||
// The first parameter's annotation contains some well-formed values, and the second
|
||||
// parameter's
|
||||
// annotation is well-formed
|
||||
assertArrayEquals(methodParameterAnnotations[0].value()[1].value(), new Enum[] {Enum.ONE});
|
||||
assertArrayEquals(methodParameterAnnotations[1].value()[0].value(), new Enum[] {Enum.ONE});
|
||||
// The first parameter's annotation contains a missing value
|
||||
assertMissing(methodParameterAnnotations[0].value()[0]);
|
||||
}
|
||||
|
||||
static void constructorParameterAnnotationsTest() throws Exception {
|
||||
AnnotationAnnotation[] constructorParameterAnnotations =
|
||||
Arrays.stream(
|
||||
Test.class
|
||||
.getDeclaredConstructor(int.class, int.class)
|
||||
.getParameterAnnotations())
|
||||
.map(x -> ((AnnotationAnnotation) x[0]))
|
||||
.toArray(AnnotationAnnotation[]::new);
|
||||
// The first parameter's annotation contains some well-formed values, and the second
|
||||
// parameter's
|
||||
// annotation is well-formed
|
||||
assertArrayEquals(constructorParameterAnnotations[0].value()[1].value(), new Enum[] {Enum.ONE});
|
||||
assertArrayEquals(constructorParameterAnnotations[1].value()[0].value(), new Enum[] {Enum.ONE});
|
||||
// The first parameter's annotation contains a missing value
|
||||
assertMissing(constructorParameterAnnotations[0].value()[0]);
|
||||
}
|
||||
|
||||
static void assertArrayEquals(Object[] actual, Object[] expected) {
|
||||
if (!Arrays.equals(actual, expected)) {
|
||||
throw new AssertionError(
|
||||
"expected: " + Arrays.toString(expected) + ", was: " + Arrays.toString(actual));
|
||||
}
|
||||
}
|
||||
|
||||
static void assertMissing(EnumArrayAnnotation annotation) throws Exception {
|
||||
try {
|
||||
annotation.value();
|
||||
throw new AssertionError("expected exception");
|
||||
} catch (EnumConstantNotPresentException expected) {
|
||||
if (!expected.getMessage().equals("Enum.TWO")) {
|
||||
throw new AssertionError(
|
||||
"expected EnumConstantNotPresentException for Enum.TWO", expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
34
test/jdk/java/lang/annotation/Missing/MissingDefault.java
Normal file
34
test/jdk/java/lang/annotation/Missing/MissingDefault.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* Annotation type with a default value whose class will be missing
|
||||
* when MissingTest is run.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
public @interface MissingDefault {
|
||||
Class<?> value() default Missing.class;
|
||||
}
|
||||
150
test/jdk/java/lang/annotation/Missing/MissingTest.java
Normal file
150
test/jdk/java/lang/annotation/Missing/MissingTest.java
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2025, 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 6322301 5041778
|
||||
* @summary Verify when missing annotation classes cause exceptions
|
||||
* @compile MissingTest.java A.java B.java C.java D.java Marker.java Missing.java MissingWrapper.java MissingDefault.java
|
||||
* @clean Missing
|
||||
* @run main MissingTest
|
||||
*/
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* This test verifies that a missing annotation class leads to the
|
||||
* expected exceptional behavior; a missing directly applied
|
||||
* annotation is currently ignored but a missing annotation value
|
||||
* inside another annotation throws an exception.
|
||||
*
|
||||
* To be run as intended, the annotation type Missing should *not* be
|
||||
* on the classpath when the test is run; with jtreg, it is deleted by
|
||||
* the @clean directive.
|
||||
*/
|
||||
public class MissingTest {
|
||||
/**
|
||||
* For the annotated element argument, get all its annotations and
|
||||
* see whether or not an exception is throw upon reading the
|
||||
* annotations. Additionally, verify at least one annotation is
|
||||
* present.
|
||||
*/
|
||||
private static void testAnnotation(AnnotatedElement element,
|
||||
boolean exceptionExpected) {
|
||||
java.lang.annotation.Annotation[] annotations;
|
||||
try {
|
||||
annotations = element.getAnnotations();
|
||||
if (exceptionExpected) {
|
||||
System.err.println("Error: Did not get an exception reading annotations on "
|
||||
+ element);
|
||||
System.err.println("Annotations found: "
|
||||
+ java.util.Arrays.toString(annotations));
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (annotations.length == 0) {
|
||||
System.err.println("Error: no annotations found on " + element);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (!exceptionExpected) {
|
||||
System.err.println("Error: Got an unexpected exception reading annotations on "
|
||||
+ element);
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For the annotated element argument, get all its annotations and
|
||||
* see whether or not an exception is throw upon reading the
|
||||
* annotations. Additionally, verify at least one annotation is
|
||||
* present.
|
||||
*/
|
||||
private static void testParameterAnnotation(Method m,
|
||||
boolean exceptionExpected) {
|
||||
java.lang.annotation.Annotation[][] annotationsArray;
|
||||
try {
|
||||
annotationsArray = m.getParameterAnnotations();
|
||||
if (exceptionExpected) {
|
||||
System.err.println("Error: Did not get an exception reading annotations on method"
|
||||
+ m);
|
||||
System.err.println("Annotations found: "
|
||||
+ java.util.Arrays.toString(annotationsArray));
|
||||
throw new RuntimeException();
|
||||
}
|
||||
if (annotationsArray.length == 0 ) {
|
||||
System.err.println("Error: no parameters for " + m);
|
||||
throw new RuntimeException();
|
||||
} else {
|
||||
java.lang.annotation.Annotation[] annotations = annotationsArray[0];
|
||||
if (annotations.length == 0) {
|
||||
System.err.println("Error: no annotations on " + m);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (!exceptionExpected) {
|
||||
System.err.println("Error: Got an unexpected exception reading annotations on "
|
||||
+ m);
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testMethodGetDefaultValue(Class<?> clazz) throws Exception{
|
||||
Method m = clazz.getMethod("value", (Class<?>[])null);
|
||||
|
||||
try {
|
||||
System.out.println(m.getDefaultValue());
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (TypeNotPresentException tnpe) {
|
||||
; // Expected
|
||||
} catch (AnnotationFormatError afe) {
|
||||
throw new RuntimeException(afe);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String... args) throws Exception {
|
||||
// Class A has a directly applied annotation whose class is
|
||||
// missing.
|
||||
testAnnotation(A.class, false);
|
||||
|
||||
// Class B has a directly applied annotation whose value
|
||||
// includes to an annotation class that is missing.
|
||||
testAnnotation(B.class, true);
|
||||
|
||||
|
||||
// Class C has a directly applied parameter annotation whose
|
||||
// class is missing.
|
||||
testParameterAnnotation(C.class.getDeclaredMethod("method1", Object.class),
|
||||
false);
|
||||
|
||||
// Class D has a directly applied parameter annotation whose value
|
||||
// includes to an annotation class that is missing.
|
||||
testParameterAnnotation(D.class.getDeclaredMethod("method1", Object.class),
|
||||
true);
|
||||
// The MissingDefault annotation type has a default value of the Missing class.
|
||||
testMethodGetDefaultValue(MissingDefault.class);
|
||||
}
|
||||
}
|
||||
34
test/jdk/java/lang/annotation/Missing/MissingWrapper.java
Normal file
34
test/jdk/java/lang/annotation/Missing/MissingWrapper.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
/**
|
||||
* Annotation wrapper around an annotation whose class will be missing
|
||||
* when MissingTest is run.
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
public @interface MissingWrapper {
|
||||
Missing value();
|
||||
}
|
||||
34
test/jdk/java/lang/annotation/PackageMain.java
Normal file
34
test/jdk/java/lang/annotation/PackageMain.java
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2011, 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.
|
||||
*/
|
||||
|
||||
public class PackageMain {
|
||||
public static void main(String[] args) throws Exception {
|
||||
Class<?> c = Class.forName("foo.bar.Baz");
|
||||
System.out.println("c=" + c);
|
||||
System.out.println("cl=" + c.getClassLoader());
|
||||
Package p = c.getPackage();
|
||||
System.out.println("p=" + p);
|
||||
Deprecated d = p.getAnnotation(Deprecated.class);
|
||||
if (d == null) throw new Error();
|
||||
}
|
||||
}
|
||||
85
test/jdk/java/lang/annotation/ParameterAnnotations.java
Normal file
85
test/jdk/java/lang/annotation/ParameterAnnotations.java
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright (c) 2008, 2024, 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 6761678 8162817
|
||||
* @summary Check properties of Annotations returned from getParameterAnnotations
|
||||
* @run main ParameterAnnotations
|
||||
* @author Martin Buchholz
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.PARAMETER })
|
||||
@interface Named {
|
||||
String value();
|
||||
}
|
||||
|
||||
public class ParameterAnnotations {
|
||||
|
||||
public void nop(@Named("foo") Object foo,
|
||||
@Named("bar") Object bar) {
|
||||
}
|
||||
|
||||
void test(String[] args) throws Throwable {
|
||||
for (Method m : thisClass.getMethods()) {
|
||||
if (m.getName().equals("nop")) {
|
||||
Annotation[][] ann = m.getParameterAnnotations();
|
||||
equal(ann.length, 2);
|
||||
Annotation foo = ann[0][0];
|
||||
Annotation bar = ann[1][0];
|
||||
equal(foo.toString(), "@Named(\"foo\")");
|
||||
equal(bar.toString(), "@Named(\"bar\")");
|
||||
check(foo.equals(foo));
|
||||
check(! foo.equals(bar));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------- Infrastructure ---------------------------
|
||||
volatile int passed = 0, failed = 0;
|
||||
void pass() {passed++;}
|
||||
void fail() {failed++; Thread.dumpStack();}
|
||||
void fail(String msg) {System.err.println(msg); fail();}
|
||||
void unexpected(Throwable t) {failed++; t.printStackTrace();}
|
||||
void check(boolean cond) {if (cond) pass(); else fail();}
|
||||
void equal(Object x, Object y) {
|
||||
if (x == null ? y == null : x.equals(y)) pass();
|
||||
else fail(x + " not equal to " + y);}
|
||||
static Class<?> thisClass = new Object(){}.getClass().getEnclosingClass();
|
||||
public static void main(String[] args) throws Throwable {
|
||||
try {thisClass.getMethod("instanceMain",String[].class)
|
||||
.invoke(thisClass.newInstance(), (Object) args);}
|
||||
catch (Throwable e) {throw e.getCause();}}
|
||||
public void instanceMain(String[] args) throws Throwable {
|
||||
try {test(args);} catch (Throwable t) {unexpected(t);}
|
||||
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
|
||||
if (failed > 0) throw new AssertionError("Some tests failed");}
|
||||
}
|
||||
44
test/jdk/java/lang/annotation/RecursiveAnnotation.java
Normal file
44
test/jdk/java/lang/annotation/RecursiveAnnotation.java
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 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 5037685
|
||||
* @summary Under certain circumstances, recursive annotations disappeared
|
||||
* @author Josh Bloch
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import static java.lang.annotation.RetentionPolicy.*;
|
||||
|
||||
@Rat public class RecursiveAnnotation {
|
||||
public static void main(String[] args) {
|
||||
if (!RecursiveAnnotation.class.isAnnotationPresent(Rat.class))
|
||||
throw new RuntimeException("RecursiveAnnotation");
|
||||
|
||||
if (!Rat.class.isAnnotationPresent(Rat.class))
|
||||
throw new RuntimeException("Rat");
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RUNTIME) @Rat @interface Rat { }
|
||||
|
|
@ -0,0 +1,252 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2022, 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 TestConstructorParameterAnnotations.java
|
||||
* @run main TestConstructorParameterAnnotations
|
||||
* @compile -parameters TestConstructorParameterAnnotations.java
|
||||
* @run main TestConstructorParameterAnnotations
|
||||
*/
|
||||
|
||||
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 TestConstructorParameterAnnotations {
|
||||
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,
|
||||
StaticNestedClass3.class,
|
||||
StaticNestedClass4.class};
|
||||
|
||||
for (Class<?> clazz : classes) {
|
||||
for (Constructor<?> ctor : clazz.getConstructors()) {
|
||||
System.out.println(ctor);
|
||||
errors += checkGetParameterAnnotations(clazz, ctor);
|
||||
errors += checkGetParametersGetAnnotation(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 checkGetParametersGetAnnotation(Class<?> clazz,
|
||||
Constructor<?> ctor) {
|
||||
int errors = 0;
|
||||
int i = 0;
|
||||
ExpectedParameterAnnotations epa =
|
||||
clazz.getAnnotation(ExpectedParameterAnnotations.class);
|
||||
|
||||
for (Parameter param : ctor.getParameters() ) {
|
||||
String annotationString =
|
||||
Objects.toString(param.getAnnotation(MarkerAnnotation.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("[[]]")
|
||||
@ExpectedParameterAnnotations({"null"})
|
||||
public class NestedClass0 {
|
||||
public NestedClass0() {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[], " +
|
||||
"[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(1)"})
|
||||
public class NestedClass1 {
|
||||
public NestedClass1(@MarkerAnnotation(1) int parameter) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[], " +
|
||||
"[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " +
|
||||
"[]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(2)",
|
||||
"null"})
|
||||
public class NestedClass2 {
|
||||
public NestedClass2(@MarkerAnnotation(2) int parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[], " +
|
||||
"[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " +
|
||||
"[]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(3)",
|
||||
"null"})
|
||||
public class NestedClass3 {
|
||||
public <P> NestedClass3(@MarkerAnnotation(3) P parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[], " +
|
||||
"[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " +
|
||||
"[]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(4)",
|
||||
"null"})
|
||||
public class NestedClass4 {
|
||||
public <P, Q> NestedClass4(@MarkerAnnotation(4) P parameter1,
|
||||
Q parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[]")
|
||||
@ExpectedParameterAnnotations({"null"})
|
||||
public static class StaticNestedClass0 {
|
||||
public StaticNestedClass0() {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[@TestConstructorParameterAnnotations.MarkerAnnotation(1)]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(1)"})
|
||||
public static class StaticNestedClass1 {
|
||||
public StaticNestedClass1(@MarkerAnnotation(1) int parameter) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[@TestConstructorParameterAnnotations.MarkerAnnotation(2)], " +
|
||||
"[]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(2)",
|
||||
"null"})
|
||||
public static class StaticNestedClass2 {
|
||||
public StaticNestedClass2(@MarkerAnnotation(2) int parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[@TestConstructorParameterAnnotations.MarkerAnnotation(3)], " +
|
||||
"[]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(3)",
|
||||
"null"})
|
||||
public static class StaticNestedClass3 {
|
||||
public <P> StaticNestedClass3(@MarkerAnnotation(3) P parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations(
|
||||
"[[@TestConstructorParameterAnnotations.MarkerAnnotation(4)], " +
|
||||
"[]]")
|
||||
@ExpectedParameterAnnotations({
|
||||
"@TestConstructorParameterAnnotations.MarkerAnnotation(4)",
|
||||
"null"})
|
||||
public static class StaticNestedClass4 {
|
||||
public <P, Q> StaticNestedClass4(@MarkerAnnotation(4) P parameter1,
|
||||
Q parameter2) {}
|
||||
}
|
||||
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface MarkerAnnotation {
|
||||
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(MarkerAnnotation.class) on each element of the
|
||||
* result of getParameters() on a constructor.
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExpectedParameterAnnotations {
|
||||
String[] value();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2025, 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 7021922
|
||||
* @summary Test null handling of IncompleteAnnotationException constructor
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
public class TestIncompleteAnnotationExceptionNPE {
|
||||
public static void main(String... args) {
|
||||
int errors = 0;
|
||||
Class<? extends Annotation> annotationType = Annotation.class;
|
||||
String elementName = "name";
|
||||
|
||||
try {
|
||||
Object o = new IncompleteAnnotationException(null, null);
|
||||
errors++;
|
||||
} catch(NullPointerException npe) {
|
||||
; // Expected
|
||||
}
|
||||
|
||||
try {
|
||||
Object o = new IncompleteAnnotationException(annotationType, null);
|
||||
errors++;
|
||||
} catch(NullPointerException npe) {
|
||||
; // Expected
|
||||
}
|
||||
|
||||
try {
|
||||
Object o = new IncompleteAnnotationException(null, elementName);
|
||||
errors++;
|
||||
} catch(NullPointerException npe) {
|
||||
; // Expected
|
||||
}
|
||||
|
||||
if (errors != 0)
|
||||
throw new RuntimeException("Encountered " + errors +
|
||||
" error(s) during construction.");
|
||||
}
|
||||
}
|
||||
659
test/jdk/java/lang/annotation/TypeAnnotationReflection.java
Normal file
659
test/jdk/java/lang/annotation/TypeAnnotationReflection.java
Normal file
|
|
@ -0,0 +1,659 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2015, 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 8004698 8007073 8022343 8054304 8057804 8058595
|
||||
* @summary Unit test for type annotations
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TypeAnnotationReflection {
|
||||
public static void main(String[] args) throws Exception {
|
||||
testSuper();
|
||||
testInterfaces();
|
||||
testReturnType();
|
||||
testNested();
|
||||
testArray();
|
||||
testRunException(TestClassException.class.getDeclaredMethod("foo", (Class<?>[])null));
|
||||
testRunException(Outer2.TestClassException2.class.getDeclaredConstructor(Outer2.class));
|
||||
testClassTypeVarBounds();
|
||||
testMethodTypeVarBounds();
|
||||
testFields();
|
||||
testClassTypeVar();
|
||||
testMethodTypeVar();
|
||||
testParameterizedType();
|
||||
testNestedParameterizedType();
|
||||
testWildcardType();
|
||||
testParameterTypes();
|
||||
testParameterType();
|
||||
}
|
||||
|
||||
private static void check(boolean b) {
|
||||
if (!b)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
private static void testSuper() throws Exception {
|
||||
check(Object.class.getAnnotatedSuperclass() == null);
|
||||
check(Class.class.getAnnotatedSuperclass().getAnnotations().length == 0);
|
||||
|
||||
AnnotatedType a;
|
||||
a = TestClassArray.class.getAnnotatedSuperclass();
|
||||
Annotation[] annos = a.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("extends"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("extends2"));
|
||||
}
|
||||
|
||||
private static void testInterfaces() throws Exception {
|
||||
AnnotatedType[] as;
|
||||
as = TestClassArray.class.getAnnotatedInterfaces();
|
||||
check(as.length == 3);
|
||||
check(as[1].getAnnotations().length == 0);
|
||||
|
||||
Annotation[] annos;
|
||||
annos = as[0].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("implements serializable"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("implements2 serializable"));
|
||||
|
||||
annos = as[2].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("implements cloneable"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("implements2 cloneable"));
|
||||
}
|
||||
|
||||
private static void testReturnType() throws Exception {
|
||||
Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
Annotation[] annos = m.getAnnotatedReturnType().getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return1"));
|
||||
}
|
||||
|
||||
private static void testNested() throws Exception {
|
||||
Method m = TestClassNested.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
Annotation[] annos = m.getAnnotatedReturnType().getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("array"));
|
||||
|
||||
AnnotatedType t = m.getAnnotatedReturnType();
|
||||
t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Inner"));
|
||||
}
|
||||
|
||||
private static void testArray() throws Exception {
|
||||
Method m = TestClassArray.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedArrayType t = (AnnotatedArrayType) m.getAnnotatedReturnType();
|
||||
Annotation[] annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return1"));
|
||||
|
||||
t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType();
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
t = (AnnotatedArrayType)t.getAnnotatedGenericComponentType();
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return3"));
|
||||
|
||||
AnnotatedType tt = t.getAnnotatedGenericComponentType();
|
||||
check(!(tt instanceof AnnotatedArrayType));
|
||||
annos = tt.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("return4"));
|
||||
}
|
||||
|
||||
private static void testRunException(Executable e) throws Exception {
|
||||
AnnotatedType[] ts = e.getAnnotatedExceptionTypes();
|
||||
check(ts.length == 3);
|
||||
|
||||
AnnotatedType t;
|
||||
Annotation[] annos;
|
||||
t = ts[0];
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("RE"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("RE2"));
|
||||
|
||||
t = ts[1];
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
t = ts[2];
|
||||
annos = t.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("AIOOBE"));
|
||||
}
|
||||
|
||||
private static void testClassTypeVarBounds() throws Exception {
|
||||
Method m = TestClassTypeVarAndField.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedType ret = m.getAnnotatedReturnType();
|
||||
Annotation[] annos = ret.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
|
||||
AnnotatedType[] annotatedBounds = ((AnnotatedTypeVariable)ret).getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 2);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Object1"));
|
||||
|
||||
annos = annotatedBounds[1].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Runnable1"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("Runnable2"));
|
||||
}
|
||||
|
||||
private static void testMethodTypeVarBounds() throws Exception {
|
||||
Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null);
|
||||
AnnotatedType ret2 = m2.getAnnotatedReturnType();
|
||||
AnnotatedType[] annotatedBounds2 = ((AnnotatedTypeVariable)ret2).getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
|
||||
Annotation[] annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("M Runnable"));
|
||||
|
||||
// Check that AnnotatedTypeVariable.getAnnotatedBounds() returns jlO for a naked
|
||||
// type variable (i.e no bounds, no annotations)
|
||||
Method m4 = TestClassTypeVarAndField.class.getDeclaredMethod("foo4", (Class<?>[])null);
|
||||
AnnotatedType ret4 = m4.getAnnotatedReturnType();
|
||||
AnnotatedType[] annotatedBounds4 = ((AnnotatedTypeVariable)ret4).getAnnotatedBounds();
|
||||
check(annotatedBounds4.length == 1);
|
||||
|
||||
annos = annotatedBounds4[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
check(annotatedBounds4[0].getType().equals(Object.class));
|
||||
}
|
||||
|
||||
private static void testFields() throws Exception {
|
||||
Field f1 = TestClassTypeVarAndField.class.getDeclaredField("field1");
|
||||
AnnotatedType at;
|
||||
Annotation[] annos;
|
||||
|
||||
at = f1.getAnnotatedType();
|
||||
annos = at.getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("T1 field"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("T2 field"));
|
||||
|
||||
Field f2 = TestClassTypeVarAndField.class.getDeclaredField("field2");
|
||||
at = f2.getAnnotatedType();
|
||||
annos = at.getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
Field f3 = TestClassTypeVarAndField.class.getDeclaredField("field3");
|
||||
at = f3.getAnnotatedType();
|
||||
annos = at.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Object field"));
|
||||
}
|
||||
|
||||
private static void testClassTypeVar() throws Exception {
|
||||
TypeVariable[] typeVars = TestClassTypeVarAndField.class.getTypeParameters();
|
||||
Annotation[] annos;
|
||||
check(typeVars.length == 3);
|
||||
|
||||
// First TypeVar
|
||||
AnnotatedType[] annotatedBounds = typeVars[0].getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 2);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Object1"));
|
||||
|
||||
annos = annotatedBounds[1].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(annos[1].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("Runnable1"));
|
||||
check(((TypeAnno2)annos[1]).value().equals("Runnable2"));
|
||||
|
||||
// second TypeVar regular anno
|
||||
Annotation[] regularAnnos = typeVars[1].getAnnotations();
|
||||
check(regularAnnos.length == 1);
|
||||
check(typeVars[1].getAnnotation(TypeAnno.class).value().equals("EE"));
|
||||
|
||||
// second TypeVar
|
||||
annotatedBounds = typeVars[1].getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 1);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno2.class));
|
||||
check(((TypeAnno2)annos[0]).value().equals("EEBound"));
|
||||
|
||||
// third Typevar V declared without explicit bounds should see jlO as its bound.
|
||||
annotatedBounds = typeVars[2].getAnnotatedBounds();
|
||||
check(annotatedBounds.length == 1);
|
||||
|
||||
annos = annotatedBounds[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
check(annotatedBounds[0].getType().equals(Object.class));
|
||||
}
|
||||
|
||||
private static void testMethodTypeVar() throws Exception {
|
||||
Method m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo2", (Class<?>[])null);
|
||||
TypeVariable[] t = m2.getTypeParameters();
|
||||
check(t.length == 1);
|
||||
Annotation[] annos = t[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
AnnotatedType[] annotatedBounds2 = t[0].getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
|
||||
annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("M Runnable"));
|
||||
|
||||
// Second method
|
||||
m2 = TestClassTypeVarAndField.class.getDeclaredMethod("foo3", (Class<?>[])null);
|
||||
t = m2.getTypeParameters();
|
||||
check(t.length == 2);
|
||||
annos = t[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(annos[0].annotationType().equals(TypeAnno.class));
|
||||
check(((TypeAnno)annos[0]).value().equals("K"));
|
||||
|
||||
annotatedBounds2 = t[0].getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
|
||||
annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
|
||||
// for the naked type variable L of foo3, we should see jlO as its bound.
|
||||
annotatedBounds2 = t[1].getAnnotatedBounds();
|
||||
check(annotatedBounds2.length == 1);
|
||||
check(annotatedBounds2[0].getType().equals(Object.class));
|
||||
|
||||
annos = annotatedBounds2[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
}
|
||||
|
||||
private static void testParameterizedType() {
|
||||
// Base
|
||||
AnnotatedType[] as;
|
||||
as = TestParameterizedType.class.getAnnotatedInterfaces();
|
||||
check(as.length == 1);
|
||||
check(as[0].getAnnotations().length == 1);
|
||||
check(as[0].getAnnotation(TypeAnno.class).value().equals("M"));
|
||||
|
||||
Annotation[] annos;
|
||||
as = ((AnnotatedParameterizedType)as[0]).getAnnotatedActualTypeArguments();
|
||||
check(as.length == 2);
|
||||
annos = as[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(as[0].getAnnotation(TypeAnno.class).value().equals("S"));
|
||||
check(as[0].getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
annos = as[1].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(((TypeAnno)annos[0]).value().equals("I"));
|
||||
check(as[1].getAnnotation(TypeAnno2.class).value().equals("I2"));
|
||||
}
|
||||
|
||||
private static void testNestedParameterizedType() throws Exception {
|
||||
Method m = TestParameterizedType.class.getDeclaredMethod("foo2", (Class<?>[])null);
|
||||
AnnotatedType ret = m.getAnnotatedReturnType();
|
||||
Annotation[] annos;
|
||||
annos = ret.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno)annos[0]).value().equals("I"));
|
||||
|
||||
AnnotatedType[] args = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments();
|
||||
check(args.length == 1);
|
||||
annos = args[0].getAnnotations();
|
||||
check(annos.length == 2);
|
||||
check(((TypeAnno)annos[0]).value().equals("I1"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("I2"));
|
||||
|
||||
// check type args
|
||||
Field f = TestParameterizedType.class.getDeclaredField("theField");
|
||||
AnnotatedParameterizedType fType = (AnnotatedParameterizedType)f.getAnnotatedType();
|
||||
args = fType.getAnnotatedActualTypeArguments();
|
||||
check(args.length == 1);
|
||||
annos = args[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno2)annos[0]).value().equals("Map Arg"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("Map Arg"));
|
||||
|
||||
// check outer type type args
|
||||
fType = (AnnotatedParameterizedType)fType.getAnnotatedOwnerType();
|
||||
args = fType.getAnnotatedActualTypeArguments();
|
||||
check(args.length == 1);
|
||||
annos = args[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno2)annos[0]).value().equals("String Arg"));
|
||||
check(args[0].getAnnotation(TypeAnno2.class).value().equals("String Arg"));
|
||||
|
||||
// check outer type normal type annotations
|
||||
annos = fType.getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno)annos[0]).value().equals("FieldOuter"));
|
||||
check(fType.getAnnotation(TypeAnno.class).value().equals("FieldOuter"));
|
||||
}
|
||||
|
||||
private static void testWildcardType() throws Exception {
|
||||
Method m = TestWildcardType.class.getDeclaredMethod("foo", (Class<?>[])null);
|
||||
AnnotatedType ret = m.getAnnotatedReturnType();
|
||||
AnnotatedType[] t;
|
||||
t = ((AnnotatedParameterizedType)ret).getAnnotatedActualTypeArguments();
|
||||
check(t.length == 1);
|
||||
ret = t[0];
|
||||
|
||||
Field f = TestWildcardType.class.getDeclaredField("f1");
|
||||
AnnotatedWildcardType w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
|
||||
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
|
||||
t = w.getAnnotatedLowerBounds();
|
||||
check(t.length == 0);
|
||||
t = w.getAnnotatedUpperBounds();
|
||||
check(t.length == 1);
|
||||
Annotation[] annos;
|
||||
annos = t[0].getAnnotations();
|
||||
check(annos.length == 1);
|
||||
check(((TypeAnno)annos[0]).value().equals("2"));
|
||||
|
||||
f = TestWildcardType.class.getDeclaredField("f2");
|
||||
w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
|
||||
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
|
||||
t = w.getAnnotatedUpperBounds();
|
||||
check(t.length == 1);
|
||||
check(t[0].getType().equals(Object.class));
|
||||
annos = t[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
t = w.getAnnotatedLowerBounds();
|
||||
check(t.length == 1);
|
||||
|
||||
// for an unbounded wildcard, we should see jlO as its upperbound and null type as its lower bound.
|
||||
f = TestWildcardType.class.getDeclaredField("f3");
|
||||
w = (AnnotatedWildcardType)((AnnotatedParameterizedType)f
|
||||
.getAnnotatedType()).getAnnotatedActualTypeArguments()[0];
|
||||
t = w.getAnnotatedUpperBounds();
|
||||
check(t.length == 1);
|
||||
check(t[0].getType().equals(Object.class));
|
||||
annos = t[0].getAnnotations();
|
||||
check(annos.length == 0);
|
||||
t = w.getAnnotatedLowerBounds();
|
||||
check(t.length == 0);
|
||||
}
|
||||
|
||||
private static void testParameterTypes() throws Exception {
|
||||
// NO PARAMS
|
||||
Method m = Params.class.getDeclaredMethod("noParams", (Class<?>[])null);
|
||||
AnnotatedType[] t = m.getAnnotatedParameterTypes();
|
||||
check(t.length == 0);
|
||||
|
||||
// ONLY ANNOTATED PARAM TYPES
|
||||
Class[] argsArr = {String.class, String.class, String.class};
|
||||
m = Params.class.getDeclaredMethod("onlyAnnotated", (Class<?>[])argsArr);
|
||||
t = m.getAnnotatedParameterTypes();
|
||||
check(t.length == 3);
|
||||
|
||||
check(t[0].getAnnotations().length == 1);
|
||||
check(t[0].getAnnotation(TypeAnno.class) != null);
|
||||
check(t[0].getAnnotationsByType(TypeAnno.class)[0].value().equals("1"));
|
||||
|
||||
check(t[1].getAnnotations().length == 1);
|
||||
check(t[1].getAnnotation(TypeAnno.class) != null);
|
||||
check(t[1].getAnnotationsByType(TypeAnno.class)[0].value().equals("2"));
|
||||
|
||||
check(t[2].getAnnotations().length == 2);
|
||||
check(t[2].getAnnotations()[0].annotationType().equals(TypeAnno.class));
|
||||
check(t[2].getAnnotation(TypeAnno.class) != null);
|
||||
check(t[2].getAnnotation(TypeAnno2.class) != null);
|
||||
check(t[2].getAnnotationsByType(TypeAnno.class)[0].value().equals("3a"));
|
||||
check(t[2].getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b"));
|
||||
|
||||
// MIXED ANNOTATED PARAM TYPES
|
||||
m = Params.class.getDeclaredMethod("mixed", (Class<?>[])argsArr);
|
||||
t = m.getAnnotatedParameterTypes();
|
||||
check(t.length == 3);
|
||||
|
||||
check(t[0].getAnnotations().length == 1);
|
||||
check(t[0].getAnnotation(TypeAnno.class) != null);
|
||||
check(t[0].getAnnotationsByType(TypeAnno.class)[0].value().equals("1"));
|
||||
|
||||
check(t[1].getAnnotations().length == 0);
|
||||
check(t[1].getAnnotation(TypeAnno.class) == null);
|
||||
check(t[1].getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
check(t[2].getAnnotations().length == 2);
|
||||
check(t[2].getAnnotations()[0].annotationType().equals(TypeAnno.class));
|
||||
check(t[2].getAnnotation(TypeAnno.class) != null);
|
||||
check(t[2].getAnnotation(TypeAnno2.class) != null);
|
||||
check(t[2].getAnnotationsByType(TypeAnno.class)[0].value().equals("3a"));
|
||||
check(t[2].getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b"));
|
||||
|
||||
// NO ANNOTATED PARAM TYPES
|
||||
m = Params.class.getDeclaredMethod("unAnnotated", (Class<?>[])argsArr);
|
||||
t = m.getAnnotatedParameterTypes();
|
||||
check(t.length == 3);
|
||||
|
||||
check(t[0].getAnnotations().length == 0);
|
||||
check(t[0].getAnnotation(TypeAnno.class) == null);
|
||||
check(t[0].getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
check(t[1].getAnnotations().length == 0);
|
||||
check(t[1].getAnnotation(TypeAnno.class) == null);
|
||||
check(t[1].getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
check(t[2].getAnnotations().length == 0);
|
||||
check(t[2].getAnnotation(TypeAnno.class) == null);
|
||||
check(t[2].getAnnotation(TypeAnno2.class) == null);
|
||||
}
|
||||
|
||||
private static void testParameterType() throws Exception {
|
||||
// NO PARAMS
|
||||
Method m = Params.class.getDeclaredMethod("noParams", (Class<?>[])null);
|
||||
Parameter[] p = m.getParameters();
|
||||
check(p.length == 0);
|
||||
|
||||
// ONLY ANNOTATED PARAM TYPES
|
||||
Class[] argsArr = {String.class, String.class, String.class};
|
||||
m = Params.class.getDeclaredMethod("onlyAnnotated", (Class<?>[])argsArr);
|
||||
p = m.getParameters();
|
||||
check(p.length == 3);
|
||||
AnnotatedType t0 = p[0].getAnnotatedType();
|
||||
AnnotatedType t1 = p[1].getAnnotatedType();
|
||||
AnnotatedType t2 = p[2].getAnnotatedType();
|
||||
|
||||
check(t0.getAnnotations().length == 1);
|
||||
check(t0.getAnnotation(TypeAnno.class) != null);
|
||||
check(t0.getAnnotationsByType(TypeAnno.class)[0].value().equals("1"));
|
||||
|
||||
check(t1.getAnnotations().length == 1);
|
||||
check(t1.getAnnotation(TypeAnno.class) != null);
|
||||
check(t1.getAnnotationsByType(TypeAnno.class)[0].value().equals("2"));
|
||||
|
||||
check(t2.getAnnotations().length == 2);
|
||||
check(t2.getAnnotations()[0].annotationType().equals(TypeAnno.class));
|
||||
check(t2.getAnnotation(TypeAnno.class) != null);
|
||||
check(t2.getAnnotation(TypeAnno2.class) != null);
|
||||
check(t2.getAnnotationsByType(TypeAnno.class)[0].value().equals("3a"));
|
||||
check(t2.getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b"));
|
||||
|
||||
// MIXED ANNOTATED PARAM TYPES
|
||||
m = Params.class.getDeclaredMethod("mixed", (Class<?>[])argsArr);
|
||||
p = m.getParameters();
|
||||
check(p.length == 3);
|
||||
|
||||
t0 = p[0].getAnnotatedType();
|
||||
t1 = p[1].getAnnotatedType();
|
||||
t2 = p[2].getAnnotatedType();
|
||||
|
||||
check(t0.getAnnotations().length == 1);
|
||||
check(t0.getAnnotation(TypeAnno.class) != null);
|
||||
check(t0.getAnnotationsByType(TypeAnno.class)[0].value().equals("1"));
|
||||
|
||||
check(t1.getAnnotations().length == 0);
|
||||
check(t1.getAnnotation(TypeAnno.class) == null);
|
||||
check(t1.getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
check(t2.getAnnotations().length == 2);
|
||||
check(t2.getAnnotations()[0].annotationType().equals(TypeAnno.class));
|
||||
check(t2.getAnnotation(TypeAnno.class) != null);
|
||||
check(t2.getAnnotation(TypeAnno2.class) != null);
|
||||
check(t2.getAnnotationsByType(TypeAnno.class)[0].value().equals("3a"));
|
||||
check(t2.getAnnotationsByType(TypeAnno2.class)[0].value().equals("3b"));
|
||||
|
||||
// NO ANNOTATED PARAM TYPES
|
||||
m = Params.class.getDeclaredMethod("unAnnotated", (Class<?>[])argsArr);
|
||||
p = m.getParameters();
|
||||
check(p.length == 3);
|
||||
|
||||
t0 = p[0].getAnnotatedType();
|
||||
t1 = p[1].getAnnotatedType();
|
||||
t2 = p[2].getAnnotatedType();
|
||||
|
||||
check(t0.getAnnotations().length == 0);
|
||||
check(t0.getAnnotation(TypeAnno.class) == null);
|
||||
check(t0.getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
check(t1.getAnnotations().length == 0);
|
||||
check(t1.getAnnotation(TypeAnno.class) == null);
|
||||
check(t1.getAnnotation(TypeAnno2.class) == null);
|
||||
|
||||
check(t2.getAnnotations().length == 0);
|
||||
check(t2.getAnnotation(TypeAnno.class) == null);
|
||||
check(t2.getAnnotation(TypeAnno2.class) == null);
|
||||
}
|
||||
}
|
||||
|
||||
class Params {
|
||||
public void noParams() {}
|
||||
public void onlyAnnotated(@TypeAnno("1") String s1, @TypeAnno("2") String s2, @TypeAnno("3a") @TypeAnno2("3b") String s3) {}
|
||||
public void mixed(@TypeAnno("1") String s1, String s2, @TypeAnno("3a") @TypeAnno2("3b") String s3) {}
|
||||
public void unAnnotated(String s1, String s2, String s3) {}
|
||||
}
|
||||
|
||||
abstract class TestWildcardType {
|
||||
public <T> List<? super T> foo() { return null;}
|
||||
public Class<@TypeAnno("1") ? extends @TypeAnno("2") Annotation> f1;
|
||||
public Class<@TypeAnno("3") ? super @TypeAnno("4") Annotation> f2;
|
||||
public Class<@TypeAnno("5") ?> f3;
|
||||
}
|
||||
|
||||
abstract class TestParameterizedType implements @TypeAnno("M") Map<@TypeAnno("S")String, @TypeAnno("I") @TypeAnno2("I2")Integer> {
|
||||
public ParameterizedOuter<String>.ParameterizedInner<Integer> foo() {return null;}
|
||||
public @TypeAnno("O") ParameterizedOuter<@TypeAnno("S1") @TypeAnno2("S2") String>.
|
||||
@TypeAnno("I") ParameterizedInner<@TypeAnno("I1") @TypeAnno2("I2")Integer> foo2() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public @TypeAnno("FieldOuter") ParameterizedOuter<@TypeAnno2("String Arg") String>.
|
||||
@TypeAnno("FieldInner")ParameterizedInner<@TypeAnno2("Map Arg")Map> theField;
|
||||
}
|
||||
|
||||
class ParameterizedOuter <T> {
|
||||
class ParameterizedInner <U> {}
|
||||
}
|
||||
|
||||
abstract class TestClassArray extends @TypeAnno("extends") @TypeAnno2("extends2") Object
|
||||
implements @TypeAnno("implements serializable") @TypeAnno2("implements2 serializable") Serializable,
|
||||
Readable,
|
||||
@TypeAnno("implements cloneable") @TypeAnno2("implements2 cloneable") Cloneable {
|
||||
public @TypeAnno("return4") Object @TypeAnno("return1") [][] @TypeAnno("return3")[] foo() { return null; }
|
||||
}
|
||||
|
||||
abstract class TestClassNested {
|
||||
public @TypeAnno("Outer") Outer.@TypeAnno("Inner")Inner @TypeAnno("array")[] foo() { return null; }
|
||||
}
|
||||
|
||||
class Outer {
|
||||
class Inner {
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TestClassException {
|
||||
public Object foo() throws @TypeAnno("RE") @TypeAnno2("RE2") RuntimeException,
|
||||
NullPointerException,
|
||||
@TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class Outer2 {
|
||||
abstract class TestClassException2 {
|
||||
public TestClassException2() throws
|
||||
@TypeAnno("RE") @TypeAnno2("RE2") RuntimeException,
|
||||
NullPointerException,
|
||||
@TypeAnno("AIOOBE") ArrayIndexOutOfBoundsException {}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class TestClassTypeVarAndField <T extends @TypeAnno("Object1") Object
|
||||
& @TypeAnno("Runnable1") @TypeAnno2("Runnable2") Runnable,
|
||||
@TypeAnno("EE")EE extends @TypeAnno2("EEBound") Runnable, V > {
|
||||
@TypeAnno("T1 field") @TypeAnno2("T2 field") T field1;
|
||||
T field2;
|
||||
@TypeAnno("Object field") Object field3;
|
||||
|
||||
public @TypeAnno("t1") @TypeAnno2("t2") T foo(){ return null; }
|
||||
public <M extends @TypeAnno("M Runnable") Runnable> M foo2() {return null;}
|
||||
public <@TypeAnno("K") K extends Cloneable, L> K foo3() {return null;}
|
||||
public <L> L foo4() {return null;}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TypeAnno {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface TypeAnno2 {
|
||||
String value();
|
||||
}
|
||||
120
test/jdk/java/lang/annotation/TypeParamAnnotation.java
Normal file
120
test/jdk/java/lang/annotation/TypeParamAnnotation.java
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8004698 8007278
|
||||
* @summary Unit test for annotations on TypeVariables
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
public class TypeParamAnnotation {
|
||||
public static void main(String[] args) throws Exception {
|
||||
testOnClass();
|
||||
testOnMethod();
|
||||
testGetAnno();
|
||||
testGetAnnos();
|
||||
}
|
||||
|
||||
private static void check(boolean b) {
|
||||
if (!b)
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
private static void testOnClass() {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getTypeParameters();
|
||||
check(ts.length == 3);
|
||||
|
||||
Annotation[] as;
|
||||
|
||||
as = ts[0].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("t"));
|
||||
check(((ParamAnno2)as[1]).value() == 1);
|
||||
|
||||
as = ts[1].getAnnotations();
|
||||
check(as.length == 0);
|
||||
|
||||
as = ts[2].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("v"));
|
||||
check(((ParamAnno2)as[1]).value() == 2);
|
||||
}
|
||||
private static void testOnMethod() throws Exception {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters();
|
||||
check(ts.length == 3);
|
||||
|
||||
Annotation[] as;
|
||||
|
||||
as = ts[0].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("x"));
|
||||
check(((ParamAnno2)as[1]).value() == 3);
|
||||
|
||||
as = ts[1].getAnnotations();
|
||||
check(as.length == 0);
|
||||
|
||||
as = ts[2].getAnnotations();
|
||||
check(as.length == 2);
|
||||
check(((ParamAnno)as[0]).value().equals("z"));
|
||||
check(((ParamAnno2)as[1]).value() == 4);
|
||||
}
|
||||
|
||||
private static void testGetAnno() {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getTypeParameters();
|
||||
ParamAnno a;
|
||||
a = ts[0].getAnnotation(ParamAnno.class);
|
||||
check(a.value().equals("t"));
|
||||
}
|
||||
private static void testGetAnnos() throws Exception {
|
||||
TypeVariable<?>[] ts = TypeParam.class.getDeclaredMethod("foo").getTypeParameters();
|
||||
ParamAnno2[] as;
|
||||
as = ts[0].getAnnotationsByType(ParamAnno2.class);
|
||||
check(as.length == 1);
|
||||
check(as[0].value() == 3);
|
||||
}
|
||||
}
|
||||
|
||||
class TypeParam <@ParamAnno("t") @ParamAnno2(1) T,
|
||||
U,
|
||||
@ParamAnno("v") @ParamAnno2(2) V extends Runnable> {
|
||||
public <@ParamAnno("x") @ParamAnno2(3) X,
|
||||
Y,
|
||||
@ParamAnno("z") @ParamAnno2(4) Z extends Cloneable> void foo() {}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ParamAnno {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ParamAnno2 {
|
||||
int value();
|
||||
}
|
||||
129
test/jdk/java/lang/annotation/TypeVariableBounds.java
Normal file
129
test/jdk/java/lang/annotation/TypeVariableBounds.java
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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 8038994
|
||||
* @summary Test that getAnnotatedBounds().getType() match getBounds()
|
||||
* @run testng TypeVariableBounds
|
||||
*/
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class TypeVariableBounds {
|
||||
@Test(dataProvider = "classData")
|
||||
public void testClass(Class<?> c) throws Exception {
|
||||
assertNotEquals(c.getTypeParameters().length, 0);
|
||||
|
||||
TypeVariable[] tv = c.getTypeParameters();
|
||||
|
||||
for(TypeVariable t : tv)
|
||||
testTv(t);
|
||||
|
||||
}
|
||||
|
||||
@Test(dataProvider = "methodData")
|
||||
public void testMethod(Class<?>c) throws Exception {
|
||||
Method m = c.getMethod("aMethod");
|
||||
TypeVariable[] tv = m.getTypeParameters();
|
||||
|
||||
for(TypeVariable t : tv)
|
||||
testTv(t);
|
||||
|
||||
}
|
||||
|
||||
public void testTv(TypeVariable<?> tv) {
|
||||
Type[] t = tv.getBounds();
|
||||
AnnotatedType[] at = tv.getAnnotatedBounds();
|
||||
|
||||
assertEquals(t.length, at.length, Arrays.asList(t) + " and " + Arrays.asList(at) + " should be the same length");
|
||||
|
||||
for (int i = 0; i < t.length; i++)
|
||||
assertSame(at[i].getType(), t[i], "T: " + t[i] + ", AT: " + at[i] + ", AT.getType(): " + at[i].getType() + "\n");
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] classData() { return CLASS_TESTS; }
|
||||
|
||||
@DataProvider
|
||||
public Object[][] methodData() { return METHOD_TESTS; }
|
||||
|
||||
public static final Object[][] CLASS_TESTS = {
|
||||
{ Case1.class, },
|
||||
{ Case2.class, },
|
||||
{ Case5.class, },
|
||||
{ Case6.class, },
|
||||
};
|
||||
|
||||
public static final Object[][] METHOD_TESTS = {
|
||||
{ Case3.class, },
|
||||
{ Case4.class, },
|
||||
{ Case5.class, },
|
||||
{ Case6.class, },
|
||||
};
|
||||
|
||||
// Class type var
|
||||
public static class Case1<C1T1, C1T2 extends AnnotatedElement, C1T3 extends AnnotatedElement & Type & Serializable> {}
|
||||
public static class Case2<C2T0, @TA C2T1 extends Type, C2T2 extends @TB AnnotatedElement, C2T3 extends AnnotatedElement & @TB Type & Serializable> {}
|
||||
|
||||
// Method type var
|
||||
public static class Case3 { public <C3T1, C3T2 extends AnnotatedElement, C3T3 extends AnnotatedElement & Type & Serializable> void aMethod() {}}
|
||||
public static class Case4 { public <C4T0, @TA C4T1 extends List, C4T2 extends @TB Set, C4T3 extends Set & @TB Callable & Serializable> void aMethod() {}}
|
||||
|
||||
// Both
|
||||
public static class Case5 <C5CT1, C5CT2 extends Runnable> {
|
||||
public <C5MT1,
|
||||
C5MT2 extends AnnotatedElement,
|
||||
C5MT3 extends AnnotatedElement & Type & Serializable,
|
||||
C5MT4 extends C5CT2>
|
||||
void aMethod() {}}
|
||||
|
||||
public static class Case6 <@TA C6CT1, C6CT2 extends @TB Runnable> {
|
||||
public <@TA C6MT1,
|
||||
C6MT2 extends @TB AnnotatedElement,
|
||||
C6MT3 extends @TB AnnotatedElement & @TB2 Type & Serializable,
|
||||
C6MT4 extends @TB2 C6CT2>
|
||||
void aMethod() {}}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
public @interface TA {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface TB {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface TB2 {}
|
||||
}
|
||||
4981
test/jdk/java/lang/annotation/UnitTest.java
Normal file
4981
test/jdk/java/lang/annotation/UnitTest.java
Normal file
File diff suppressed because it is too large
Load diff
37
test/jdk/java/lang/annotation/package-info.java
Normal file
37
test/jdk/java/lang/annotation/package-info.java
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2004, 2011, 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 4901290 5037531
|
||||
* @summary Package annotations
|
||||
* @author gafter
|
||||
*
|
||||
* @compile package-info.java PackageMain.java
|
||||
* @run main PackageMain
|
||||
*/
|
||||
|
||||
@Deprecated
|
||||
package foo.bar;
|
||||
|
||||
class Baz {}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8027170
|
||||
* @summary getAnnotationsByType needs to take the class hierarchy into account
|
||||
* when determining which annotations are associated with a given
|
||||
* class.
|
||||
* @run main InheritedAssociatedAnnotations
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class InheritedAssociatedAnnotations {
|
||||
|
||||
public static void main(String[] args) {
|
||||
checkAssociated(A3.class);
|
||||
checkAssociated(B3.class);
|
||||
checkAssociated(C3.class);
|
||||
checkAssociated(D3.class);
|
||||
}
|
||||
|
||||
private static void checkAssociated(AnnotatedElement ae) {
|
||||
Ann[] actual = ae.getAnnotationsByType(Ann.class);
|
||||
Ann[] expected = ae.getAnnotation(ExpectedAssociated.class).value();
|
||||
|
||||
if (!Arrays.equals(actual, expected)) {
|
||||
throw new RuntimeException(String.format(
|
||||
"Test failed for %s: Expected %s but got %s.",
|
||||
ae,
|
||||
Arrays.toString(expected),
|
||||
Arrays.toString(actual)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface ExpectedAssociated {
|
||||
Ann[] value();
|
||||
}
|
||||
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Repeatable(AnnCont.class)
|
||||
@interface Ann {
|
||||
int value();
|
||||
}
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@interface AnnCont {
|
||||
Ann[] value();
|
||||
}
|
||||
|
||||
|
||||
@Ann(10)
|
||||
class A1 {}
|
||||
|
||||
@Ann(20)
|
||||
class A2 extends A1 {}
|
||||
|
||||
@ExpectedAssociated({@Ann(20)})
|
||||
class A3 extends A2 {}
|
||||
|
||||
|
||||
@Ann(10) @Ann(11)
|
||||
class B1 {}
|
||||
|
||||
@Ann(20)
|
||||
class B2 extends B1 {}
|
||||
|
||||
@ExpectedAssociated({@Ann(20)})
|
||||
class B3 extends B2 {}
|
||||
|
||||
|
||||
@Ann(10)
|
||||
class C1 {}
|
||||
|
||||
@Ann(20) @Ann(21)
|
||||
class C2 extends C1 {}
|
||||
|
||||
@ExpectedAssociated({@Ann(20), @Ann(21)})
|
||||
class C3 extends C2 {}
|
||||
|
||||
|
||||
@Ann(10) @Ann(11)
|
||||
class D1 {}
|
||||
|
||||
@Ann(20) @Ann(21)
|
||||
class D2 extends D1 {}
|
||||
|
||||
@ExpectedAssociated({@Ann(20), @Ann(21)})
|
||||
class D3 extends D2 {}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8019420
|
||||
* @summary Repeatable non-inheritable annotation types are mishandled by Core Reflection
|
||||
*/
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class NonInheritableContainee {
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(InheritedAnnotationContainer.class)
|
||||
@interface NonInheritedAnnotationRepeated {
|
||||
String name();
|
||||
}
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface InheritedAnnotationContainer {
|
||||
NonInheritedAnnotationRepeated[] value();
|
||||
}
|
||||
|
||||
@NonInheritedAnnotationRepeated(name="A")
|
||||
@NonInheritedAnnotationRepeated(name="B")
|
||||
class Parent {}
|
||||
class Sample extends Parent {}
|
||||
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
Annotation[] anns = Sample.class.getAnnotationsByType(
|
||||
NonInheritedAnnotationRepeated.class);
|
||||
|
||||
if (anns.length != 0)
|
||||
throw new RuntimeException("Non-@Inherited containees should not " +
|
||||
"be inherited even though its container is @Inherited.");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8004912
|
||||
* @summary Unit test for order of annotations returned by get[Declared]AnnotationsByType.
|
||||
*
|
||||
* @run main OrderUnitTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class OrderUnitTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
testOrder(Case1.class);
|
||||
testOrder(Case2.class);
|
||||
}
|
||||
|
||||
private static void testOrder(AnnotatedElement e) {
|
||||
Annotation[] decl = e.getDeclaredAnnotations();
|
||||
Foo[] declByType = e.getDeclaredAnnotationsByType(Foo.class);
|
||||
|
||||
if (decl[0] instanceof Foo != declByType[0].isDirect() ||
|
||||
decl[1] instanceof Foo != declByType[1].isDirect()) {
|
||||
throw new RuntimeException("Order of directly / indirectly present " +
|
||||
"annotations from getDeclaredAnnotationsByType does not " +
|
||||
"match order from getDeclaredAnnotations.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface FooContainer {
|
||||
Foo[] value();
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(FooContainer.class)
|
||||
@interface Foo {
|
||||
boolean isDirect();
|
||||
}
|
||||
|
||||
|
||||
@Foo(isDirect = true) @FooContainer({@Foo(isDirect = false)})
|
||||
class Case1 {
|
||||
}
|
||||
|
||||
|
||||
@FooContainer({@Foo(isDirect = false)}) @Foo(isDirect = true)
|
||||
class Case2 {
|
||||
}
|
||||
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 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 7154390 8005712 8007278 8004912
|
||||
* @summary Unit test for repeated annotation reflection
|
||||
*
|
||||
* @compile RepeatedUnitTest.java subpackage/package-info.java subpackage/Container.java subpackage/Containee.java subpackage/NonRepeated.java subpackage/InheritedContainee.java subpackage/InheritedContainer.java subpackage/InheritedNonRepeated.java
|
||||
* @run main RepeatedUnitTest
|
||||
*/
|
||||
|
||||
import subpackage.*;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
|
||||
public class RepeatedUnitTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
// PACKAGE ANNOTATIONS
|
||||
Class c = Class.forName("subpackage.NonRepeated"); // force package "subpackage" load
|
||||
Package p = Package.getPackage("subpackage");
|
||||
packageNonRepeated(p);
|
||||
packageRepeated(p);
|
||||
packageContainer(p);
|
||||
|
||||
// INHERITED/NON-INHERITED ON CLASS
|
||||
inheritedMe1();
|
||||
inheritedMe2();
|
||||
inheritedMe3();
|
||||
inheritedMe4();
|
||||
|
||||
inheritedMe5(); // ContainerOnSuperSingleOnSub
|
||||
inheritedMe6(); // RepeatableOnSuperSingleOnSub
|
||||
inheritedMe7(); // SingleAnnoOnSuperContainerOnSub
|
||||
inheritedMe8(); // SingleOnSuperRepeatableOnSub
|
||||
|
||||
|
||||
// CONSTRUCTOR
|
||||
checkMultiplier(Me1.class.getConstructor(new Class[0]), 10);
|
||||
|
||||
// FIELD
|
||||
checkMultiplier(Me1.class.getField("foo"), 1);
|
||||
|
||||
// METHOD
|
||||
checkMultiplier(Me1.class.getDeclaredMethod("mee", (Class<?>[])null), 100);
|
||||
|
||||
// INNER CLASS
|
||||
checkMultiplier(Me1.MiniMee.class, 1000);
|
||||
|
||||
// ENUM ELEMENT
|
||||
checkMultiplier(Me1.E.class.getField("EE"), 10000);
|
||||
|
||||
// ENUM
|
||||
checkMultiplier(Me1.E.class, 100000);
|
||||
}
|
||||
|
||||
static void packageNonRepeated(AnnotatedElement e) {
|
||||
NonRepeated nr = e.getAnnotation(NonRepeated.class);
|
||||
check(nr.value() == 10);
|
||||
|
||||
check(1 == countAnnotation(e, NonRepeated.class));
|
||||
|
||||
nr = e.getAnnotationsByType(NonRepeated.class)[0];
|
||||
check(nr.value() == 10);
|
||||
|
||||
check(1 == containsAnnotationOfType(e.getAnnotations(), NonRepeated.class));
|
||||
}
|
||||
|
||||
static void packageRepeated(AnnotatedElement e) {
|
||||
Containee c = e.getAnnotation(Containee.class);
|
||||
check(c == null);
|
||||
check(2 == countAnnotation(e, Containee.class));
|
||||
|
||||
c = e.getAnnotationsByType(Containee.class)[0];
|
||||
check(c.value() == 1);
|
||||
c = e.getAnnotationsByType(Containee.class)[1];
|
||||
check(c.value() == 2);
|
||||
|
||||
check(0 == containsAnnotationOfType(e.getAnnotations(), Containee.class));
|
||||
}
|
||||
|
||||
static void packageContainer(AnnotatedElement e) {
|
||||
Container cr = e.getAnnotation(Container.class);
|
||||
check(null != cr);
|
||||
check(1 == containsAnnotationOfType(e.getAnnotationsByType(Container.class), Container.class));
|
||||
check(1 == countAnnotation(e, Container.class));
|
||||
}
|
||||
|
||||
static void inheritedMe1() {
|
||||
AnnotatedElement e = Me1.class;
|
||||
check(null == e.getAnnotation(NonRepeated.class));
|
||||
check(e.getAnnotation(InheritedNonRepeated.class).value() == 20);
|
||||
check(0 == countAnnotation(e, Containee.class));
|
||||
check(4 == countAnnotation(e, InheritedContainee.class));
|
||||
check(0 == countAnnotation(e, Container.class));
|
||||
check(1 == countAnnotation(e, InheritedContainer.class));
|
||||
}
|
||||
|
||||
static void inheritedMe2() {
|
||||
AnnotatedElement e = Me2.class;
|
||||
check(e.getAnnotation(NonRepeated.class).value() == 100);
|
||||
check(e.getAnnotation(InheritedNonRepeated.class).value() == 200);
|
||||
check(4 == countAnnotation(e, Containee.class));
|
||||
check(4 == countAnnotation(e, InheritedContainee.class));
|
||||
check(1 == countAnnotation(e, Container.class));
|
||||
check(1 == countAnnotation(e, InheritedContainer.class));
|
||||
check(1 == countAnnotation(e, NonRepeated.class));
|
||||
check(1 == countAnnotation(e, InheritedNonRepeated.class));
|
||||
|
||||
check(e.getAnnotationsByType(Containee.class)[2].value() == 300);
|
||||
check(e.getAnnotationsByType(InheritedContainee.class)[2].value() == 300);
|
||||
check(e.getAnnotationsByType(InheritedNonRepeated.class)[0].value() == 200);
|
||||
check(e.getAnnotationsByType(NonRepeated.class)[0].value() == 100);
|
||||
}
|
||||
|
||||
static void inheritedMe3() {
|
||||
AnnotatedElement e = Me3.class;
|
||||
check(null == e.getAnnotation(NonRepeated.class));
|
||||
|
||||
check(0 == countAnnotation(e, Containee.class));
|
||||
check(4 == countAnnotation(e, InheritedContainee.class));
|
||||
check(0 == countAnnotation(e, Container.class));
|
||||
check(1 == countAnnotation(e, InheritedContainer.class));
|
||||
|
||||
check(e.getAnnotationsByType(InheritedContainee.class)[2].value() == 350);
|
||||
check(e.getAnnotationsByType(InheritedNonRepeated.class)[0].value() == 15);
|
||||
}
|
||||
|
||||
static void inheritedMe4() {
|
||||
AnnotatedElement e = Me4.class;
|
||||
check(e.getAnnotation(NonRepeated.class).value() == 1000);
|
||||
check(e.getAnnotation(InheritedNonRepeated.class).value() == 2000);
|
||||
check(4 == countAnnotation(e, Containee.class));
|
||||
check(4 == countAnnotation(e, InheritedContainee.class));
|
||||
check(1 == countAnnotation(e, Container.class));
|
||||
check(1 == countAnnotation(e, InheritedContainer.class));
|
||||
check(1 == countAnnotation(e, NonRepeated.class));
|
||||
check(1 == countAnnotation(e, InheritedNonRepeated.class));
|
||||
|
||||
check(e.getAnnotationsByType(Containee.class)[2].value() == 3000);
|
||||
check(e.getAnnotationsByType(InheritedContainee.class)[2].value() == 3000);
|
||||
check(e.getAnnotationsByType(InheritedNonRepeated.class)[0].value() == 2000);
|
||||
check(e.getAnnotationsByType(NonRepeated.class)[0].value() == 1000);
|
||||
}
|
||||
|
||||
static void inheritedMe5() {
|
||||
AnnotatedElement e = Me5.class;
|
||||
check(2 == e.getAnnotations().length);
|
||||
check(1 == countAnnotation(e, InheritedContainee.class));
|
||||
}
|
||||
|
||||
static void inheritedMe6() {
|
||||
AnnotatedElement e = Me6.class;
|
||||
check(2 == e.getAnnotations().length);
|
||||
check(1 == countAnnotation(e, InheritedContainee.class));
|
||||
}
|
||||
|
||||
static void inheritedMe7() {
|
||||
AnnotatedElement e = Me7.class;
|
||||
check(2 == e.getAnnotations().length);
|
||||
check(2 == countAnnotation(e, InheritedContainee.class));
|
||||
}
|
||||
|
||||
static void inheritedMe8() {
|
||||
AnnotatedElement e = Me8.class;
|
||||
check(2 == e.getAnnotations().length);
|
||||
check(2 == countAnnotation(e, InheritedContainee.class));
|
||||
}
|
||||
|
||||
static void checkMultiplier(AnnotatedElement e, int m) {
|
||||
// Basic sanity of non-repeating getAnnotation(Class)
|
||||
check(e.getAnnotation(NonRepeated.class).value() == 5 * m);
|
||||
|
||||
// Check count of annotations returned from getAnnotationsByType(Class)
|
||||
check(4 == countAnnotation(e, Containee.class));
|
||||
check(1 == countAnnotation(e, Container.class));
|
||||
check(1 == countAnnotation(e, NonRepeated.class));
|
||||
|
||||
// Check contents of array returned from getAnnotationsByType(Class)
|
||||
check(e.getAnnotationsByType(Containee.class)[2].value() == 3 * m);
|
||||
check(e.getAnnotationsByType(NonRepeated.class)[0].value() == 5 * m);
|
||||
|
||||
// Check getAnnotation(Class)
|
||||
check(e.getAnnotation(Containee.class) == null);
|
||||
check(e.getAnnotation(Container.class) != null);
|
||||
|
||||
// Check count of annotations returned from getAnnotations()
|
||||
check(0 == containsAnnotationOfType(e.getAnnotations(), Containee.class));
|
||||
check(1 == containsAnnotationOfType(e.getAnnotations(), Container.class));
|
||||
check(1 == containsAnnotationOfType(e.getAnnotations(), NonRepeated.class));
|
||||
}
|
||||
|
||||
static void check(Boolean b) {
|
||||
if (!b) throw new RuntimeException();
|
||||
}
|
||||
|
||||
static int countAnnotation(AnnotatedElement e, Class<? extends Annotation> c) {
|
||||
return containsAnnotationOfType(e.getAnnotationsByType(c), c);
|
||||
}
|
||||
|
||||
static <A extends Annotation> int containsAnnotationOfType(A[] l, Class<? extends Annotation> a) {
|
||||
int count = 0;
|
||||
for (Annotation an : l) {
|
||||
if (an.annotationType().equals(a))
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
@NonRepeated @InheritedNonRepeated
|
||||
@InheritedContainee(1) @InheritedContainee(2) @InheritedContainee(3) @InheritedContainee(4)
|
||||
@Containee(1) @Containee(2) @Containee(3) @Containee(4)
|
||||
class Grandma {}
|
||||
|
||||
class Mother extends Grandma {}
|
||||
|
||||
@NonRepeated(5) @InheritedNonRepeated(15)
|
||||
@InheritedContainee(150) @InheritedContainee(250) @InheritedContainee(350) @InheritedContainee(450)
|
||||
@Containee(150) @Containee(250) @Containee(350) @Containee(450)
|
||||
class Father extends Grandma {}
|
||||
|
||||
class Me1 extends Mother {
|
||||
|
||||
@NonRepeated(5)
|
||||
@Containee(1) @Containee(2) @Containee(3) @Containee(4)
|
||||
public String foo = "";
|
||||
|
||||
@NonRepeated(50)
|
||||
@Containee(10) @Containee(20) @Containee(30) @Containee(40)
|
||||
public Me1() {
|
||||
}
|
||||
|
||||
@NonRepeated(500)
|
||||
@Containee(100) @Containee(200) @Containee(300) @Containee(400)
|
||||
public void mee() {
|
||||
}
|
||||
|
||||
@NonRepeated(5000)
|
||||
@Containee(1000) @Containee(2000) @Containee(3000) @Containee(4000)
|
||||
public class MiniMee {}
|
||||
|
||||
@NonRepeated(500000)
|
||||
@Containee(100000) @Containee(200000) @Containee(300000) @Containee(400000)
|
||||
public enum E {
|
||||
@NonRepeated(50000)
|
||||
@Containee(10000) @Containee(20000) @Containee(30000) @Containee(40000)
|
||||
EE(),
|
||||
}
|
||||
}
|
||||
|
||||
@NonRepeated(100) @InheritedNonRepeated(200)
|
||||
@InheritedContainee(100) @InheritedContainee(200) @InheritedContainee(300) @InheritedContainee(400)
|
||||
@Containee(100) @Containee(200) @Containee(300) @Containee(400)
|
||||
class Me2 extends Mother {}
|
||||
|
||||
class Me3 extends Father {}
|
||||
|
||||
@NonRepeated(1000) @InheritedNonRepeated(2000)
|
||||
@InheritedContainee(1000) @InheritedContainee(2000) @InheritedContainee(3000) @InheritedContainee(4000)
|
||||
@Containee(1000) @Containee(2000) @Containee(3000) @Containee(4000)
|
||||
class Me4 extends Father {}
|
||||
|
||||
|
||||
@InheritedContainer({@InheritedContainee(1), @InheritedContainee(2)})
|
||||
class SuperOf5 {}
|
||||
|
||||
@InheritedContainee(3)
|
||||
class Me5 extends SuperOf5{}
|
||||
|
||||
|
||||
@InheritedContainee(1) @InheritedContainee(2)
|
||||
class SuperOf6 {}
|
||||
|
||||
@InheritedContainee(3)
|
||||
class Me6 extends SuperOf6 {}
|
||||
|
||||
|
||||
@InheritedContainee(1)
|
||||
class SuperOf7 {}
|
||||
|
||||
@InheritedContainer({@InheritedContainee(2), @InheritedContainee(3)})
|
||||
class Me7 extends SuperOf7 {}
|
||||
|
||||
|
||||
@InheritedContainee(1)
|
||||
class SuperOf8 {}
|
||||
|
||||
@InheritedContainee(2) @InheritedContainee(3)
|
||||
class Me8 extends SuperOf8 {}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 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.
|
||||
*/
|
||||
|
||||
package subpackage;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(Container.class)
|
||||
public @interface Containee {
|
||||
int value();
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 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.
|
||||
*/
|
||||
|
||||
package subpackage;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Container {
|
||||
Containee[] value();
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 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.
|
||||
*/
|
||||
|
||||
package subpackage;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(InheritedContainer.class)
|
||||
public @interface InheritedContainee {
|
||||
int value();
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2013, 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.
|
||||
*/
|
||||
|
||||
package subpackage;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InheritedContainer {
|
||||
InheritedContainee[] value();
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
package subpackage;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Inherited
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface InheritedNonRepeated {
|
||||
int value() default 20;
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
package subpackage;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface NonRepeated {
|
||||
int value() default 10;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 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.
|
||||
*/
|
||||
|
||||
@NonRepeated @Containee(1) @Containee(2)
|
||||
package subpackage;
|
||||
106
test/jdk/java/lang/annotation/typeAnnotations/BadCPIndex.java
Normal file
106
test/jdk/java/lang/annotation/typeAnnotations/BadCPIndex.java
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8023878
|
||||
* @summary Test that the right kind of exception is thrown from the type
|
||||
* annotation reflection code.
|
||||
* @run testng BadCPIndex
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.util.Base64;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.DataProvider;
|
||||
|
||||
public class BadCPIndex {
|
||||
private static final MyLoader loader = new MyLoader(BadCPIndex.class.getClassLoader());
|
||||
|
||||
// Blueprint for broken C
|
||||
//public static class C extends @BadCPIndex.A Object {}
|
||||
private static final String encodedBrokenC = "yv66vgAAADQAFgoAAwAPBwARBwATAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAClNvdXJjZUZpbGUBAA9CYWRDUEluZGV4LmphdmEBAB1SdW50aW1lVmlzaWJsZVR5cGVBbm5vdGF0aW9ucwcAFAEAAUEBAAxJbm5lckNsYXNzZXMBAA5MQmFkQ1BJbmRleCRBOwwABAAFBwAVAQAMQmFkQ1BJbmRleCRDAQABQwEAEGphdmEvbGFuZy9PYmplY3QBAAxCYWRDUEluZGV4JEEBAApCYWRDUEluZGV4ACEAAgADAAAAAAABAAEABAAFAAEABgAAAB0AAQABAAAABSq3AAGxAAAAAQAHAAAABgABAAAAKQADAAgAAAACAAkACgAAAAoAARD//wAADwAAAA0AAAASAAIACwAQAAwmCQACABAAEgAJ";
|
||||
|
||||
// Blueprint for broken D
|
||||
//public static class D<@BadCPIndex.B U> {}
|
||||
private static final String encodedBrokenD = "yv66vgAAADQAGAoAAwARBwATBwAVAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEACVNpZ25hdHVyZQEAKDxVOkxqYXZhL2xhbmcvT2JqZWN0Oz5MamF2YS9sYW5nL09iamVjdDsBAApTb3VyY2VGaWxlAQAPQmFkQ1BJbmRleC5qYXZhAQAdUnVudGltZVZpc2libGVUeXBlQW5ub3RhdGlvbnMHABYBAAFCAQAMSW5uZXJDbGFzc2VzAQAOTEJhZENQSW5kZXgkQjsMAAQABQcAFwEADEJhZENQSW5kZXgkRAEAAUQBABBqYXZhL2xhbmcvT2JqZWN0AQAMQmFkQ1BJbmRleCRCAQAKQmFkQ1BJbmRleAAhAAIAAwAAAAAAAQABAAQABQABAAYAAAAdAAEAAQAAAAUqtwABsQAAAAEABwAAAAYAAQAAAEAABAAIAAAAAgAJAAoAAAACAAsADAAAAAkAAQAAAAARAAAADwAAABIAAgANABIADiYJAAIAEgAUAAk=";
|
||||
|
||||
// Blueprint for broken E
|
||||
//public static class E extends @BadCPIndex.A Object {}
|
||||
private static final String encodedBrokenE = "yv66vgAAADQAFgoAAwAPBwARBwATAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAClNvdXJjZUZpbGUBAA9CYWRDUEluZGV4LmphdmEBAB1SdW50aW1lVmlzaWJsZVR5cGVBbm5vdGF0aW9ucwcAFAEAAUEBAAxJbm5lckNsYXNzZXMBAA5MQmFkQ1BJbmRleCRBOwwABAAFBwAVAQAMQmFkQ1BJbmRleCRFAQABRQEAEGphdmEvbGFuZy9PYmplY3QBAAxCYWRDUEluZGV4JEEBAApCYWRDUEluZGV4ACEAAgADAAAAAAABAAEABAAFAAEABgAAAB0AAQABAAAABSq3AAGxAAAAAQAHAAAABgABAAAARgADAAgAAAACAAkACgAAAAoAARD//wAADgAKAA0AAAASAAIACwAQAAwmCQACABAAEgAJ";
|
||||
|
||||
private static final Object[][] cases = {
|
||||
{ new Case("BadCPIndex$C", encodedBrokenC, Class::getAnnotatedSuperclass) },
|
||||
{ new Case("BadCPIndex$D", encodedBrokenD, (c -> c.getTypeParameters()[0].getAnnotations()))},
|
||||
{ new Case("BadCPIndex$E", encodedBrokenE, Class::getAnnotatedSuperclass) },
|
||||
};
|
||||
|
||||
@DataProvider
|
||||
public static Object[][] data() { return cases; }
|
||||
|
||||
@Test(dataProvider="data")
|
||||
public static void testOpThrowsAFE(Case testCase) {
|
||||
Class<?> c = loader.defineClass(testCase.name, Base64.getDecoder().decode(testCase.encoding));
|
||||
try {
|
||||
System.out.println("Testing: " + c);
|
||||
testCase.trigger.apply(c);
|
||||
throw new RuntimeException("Expecting AnnotationFormatError here");
|
||||
} catch (AnnotationFormatError e) {
|
||||
; //ok
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyLoader extends ClassLoader {
|
||||
public MyLoader(ClassLoader parent) {
|
||||
super(parent);
|
||||
}
|
||||
|
||||
public Class<?> defineClass(String name, byte[] bytes) {
|
||||
return defineClass(name, bytes, 0, bytes.length);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Case {
|
||||
public String name;
|
||||
public String encoding;
|
||||
public Function<Class<?>, Object> trigger;
|
||||
|
||||
public Case(String name, String encoding, Function<Class<?>, Object> trigger) {
|
||||
this.name = name;
|
||||
this.encoding = encoding;
|
||||
this.trigger = trigger;
|
||||
}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public static @interface A {}
|
||||
|
||||
@Target(ElementType.TYPE_PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public static @interface B {}
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8023651 8044629
|
||||
* @summary Test that the receiver annotations and the return annotations of
|
||||
* constructors behave correctly.
|
||||
* @run testng ConstructorReceiverTest
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Arrays;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class ConstructorReceiverTest {
|
||||
public static final Integer EMPTY_ANNOTATED_TYPE = Integer.valueOf(-1);
|
||||
|
||||
// Format is {
|
||||
// { Class to get ctor for,
|
||||
// ctor param class,
|
||||
// value of anno of return type,
|
||||
// value of anno for receiver,
|
||||
// or null if there should be no receiver,
|
||||
// or EMPTY_ANNOTATED_TYPE of there should be a receiver but
|
||||
// no annotation
|
||||
// },
|
||||
// ...
|
||||
// }
|
||||
public static final Object[][] TESTS = {
|
||||
{ ConstructorReceiverTest.class, null, Integer.valueOf(5), null },
|
||||
{ ConstructorReceiverTest.Middle.class, ConstructorReceiverTest.class, Integer.valueOf(10), Integer.valueOf(15) },
|
||||
{ ConstructorReceiverTest.Middle.Inner.class, ConstructorReceiverTest.Middle.class, Integer.valueOf(100), Integer.valueOf(150) },
|
||||
{ ConstructorReceiverTest.Middle.Inner.Innermost.class, ConstructorReceiverTest.Middle.Inner.class, Integer.valueOf(1000), Integer.valueOf(1500) },
|
||||
{ ConstructorReceiverTest.Middle.InnerNoReceiver.class, ConstructorReceiverTest.Middle.class, Integer.valueOf(300), EMPTY_ANNOTATED_TYPE },
|
||||
{ ConstructorReceiverTest.Nested.class, null, Integer.valueOf(20), null },
|
||||
{ ConstructorReceiverTest.Nested.NestedMiddle.class, ConstructorReceiverTest.Nested.class, Integer.valueOf(200), Integer.valueOf(250)},
|
||||
{ ConstructorReceiverTest.Nested.NestedMiddle.NestedInner.class, ConstructorReceiverTest.Nested.NestedMiddle.class, Integer.valueOf(2000), Integer.valueOf(2500)},
|
||||
{ ConstructorReceiverTest.Nested.NestedMiddle.NestedInnerNoReceiver.class, ConstructorReceiverTest.Nested.NestedMiddle.class, Integer.valueOf(4000), EMPTY_ANNOTATED_TYPE},
|
||||
{ ConstructorReceiverTest.Nested.NestedMiddle.SecondNestedInnerNoReceiver.class, ConstructorReceiverTest.Nested.NestedMiddle.class, Integer.valueOf(5000), EMPTY_ANNOTATED_TYPE},
|
||||
};
|
||||
|
||||
|
||||
@DataProvider
|
||||
public Object[][] data() { return TESTS; }
|
||||
|
||||
@Test(dataProvider = "data")
|
||||
public void testAnnotatedReciver(Class<?> toTest, Class<?> ctorParamType,
|
||||
Integer returnVal, Integer receiverVal) throws NoSuchMethodException {
|
||||
Constructor c;
|
||||
if (ctorParamType == null)
|
||||
c = toTest.getDeclaredConstructor();
|
||||
else
|
||||
c = toTest.getDeclaredConstructor(ctorParamType);
|
||||
|
||||
AnnotatedType annotatedReceiverType = c.getAnnotatedReceiverType();
|
||||
|
||||
// Some Constructors doesn't conceptually have a receiver, they should return null
|
||||
if (receiverVal == null) {
|
||||
assertNull(annotatedReceiverType, "getAnnotatedReciverType should return null for Constructor: " + c);
|
||||
return;
|
||||
}
|
||||
|
||||
// check that getType() matches the receiver (which can be parameterized)
|
||||
if (annotatedReceiverType.getType() instanceof ParameterizedType) {
|
||||
assertEquals(((ParameterizedType) annotatedReceiverType.getType()).getRawType(),
|
||||
ctorParamType,
|
||||
"getType() doesn't match receiver type: " + ctorParamType);
|
||||
} else {
|
||||
assertEquals(annotatedReceiverType.getType(),
|
||||
ctorParamType,
|
||||
"getType() doesn't match receiver type: " + ctorParamType);
|
||||
}
|
||||
|
||||
Annotation[] receiverAnnotations = annotatedReceiverType.getAnnotations();
|
||||
|
||||
// Some Constructors have no annotations on but in theory can have a receiver
|
||||
if (receiverVal.equals(EMPTY_ANNOTATED_TYPE)) {
|
||||
assertEquals(receiverAnnotations.length, 0, "expecting an empty annotated type for: " + c);
|
||||
return;
|
||||
}
|
||||
|
||||
// The rest should have annotations
|
||||
assertEquals(receiverAnnotations.length, 1, "expecting a 1 element array. Looking at 'length': ");
|
||||
assertEquals(((Annot)receiverAnnotations[0]).value(), receiverVal.intValue(), " wrong annotation found. Found " +
|
||||
receiverAnnotations[0] +
|
||||
" should find @Annot with value=" +
|
||||
receiverVal);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "data")
|
||||
public void testAnnotatedReturn(Class<?> toTest, Class<?> ctorParamType,
|
||||
Integer returnVal, Integer receiverVal) throws NoSuchMethodException {
|
||||
Constructor c;
|
||||
if (ctorParamType == null)
|
||||
c = toTest.getDeclaredConstructor();
|
||||
else
|
||||
c = toTest.getDeclaredConstructor(ctorParamType);
|
||||
|
||||
AnnotatedType annotatedReturnType = c.getAnnotatedReturnType();
|
||||
Annotation[] returnAnnotations = annotatedReturnType.getAnnotations();
|
||||
|
||||
assertEquals(returnAnnotations.length, 1, "expecting a 1 element array. Looking at 'length': ");
|
||||
assertEquals(((Annot)returnAnnotations[0]).value(), returnVal.intValue(), " wrong annotation found. Found " +
|
||||
returnAnnotations[0] +
|
||||
" should find @Annot with value=" +
|
||||
returnVal);
|
||||
}
|
||||
|
||||
@Annot(5) ConstructorReceiverTest() {}
|
||||
|
||||
private class Middle {
|
||||
@Annot(10) public Middle(@Annot(15) ConstructorReceiverTest ConstructorReceiverTest.this) {}
|
||||
|
||||
public class Inner {
|
||||
@Annot(100) Inner(@Annot(150) Middle Middle.this) {}
|
||||
|
||||
class Innermost {
|
||||
@Annot(1000) private Innermost(@Annot(1500) Inner Inner.this) {}
|
||||
}
|
||||
}
|
||||
|
||||
class InnerNoReceiver {
|
||||
@Annot(300) InnerNoReceiver(Middle Middle.this) {}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Nested {
|
||||
@Annot(20) public Nested() {}
|
||||
|
||||
class NestedMiddle {
|
||||
@Annot(200) public NestedMiddle(@Annot(250) Nested Nested.this) {}
|
||||
|
||||
class NestedInner {
|
||||
@Annot(2000) public NestedInner(@Annot(2500) NestedMiddle NestedMiddle.this) {}
|
||||
}
|
||||
|
||||
class NestedInnerNoReceiver {
|
||||
@Annot(4000) public NestedInnerNoReceiver() {}
|
||||
}
|
||||
|
||||
class SecondNestedInnerNoReceiver {
|
||||
@Annot(5000) public SecondNestedInnerNoReceiver(NestedMiddle NestedMiddle.this) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public static @interface Annot {
|
||||
int value();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8022324
|
||||
* @summary Test Class.getAnnotatedInterfaces() returns 0-length array as
|
||||
* specified.
|
||||
*/
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GetAnnotatedInterfaces {
|
||||
private static final Class<?>[] testData = {
|
||||
GetAnnotatedInterfaces.class,
|
||||
(new Clz() {}).getClass(),
|
||||
(new Object() {}).getClass(),
|
||||
Object[].class,
|
||||
Object[][].class,
|
||||
Object[][][].class,
|
||||
Object.class,
|
||||
void.class,
|
||||
int.class,
|
||||
};
|
||||
|
||||
private static int failed = 0;
|
||||
private static int tests = 0;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testReturnsZeroLengthArray();
|
||||
|
||||
if (failed != 0)
|
||||
throw new RuntimeException("Test failed, check log for details");
|
||||
if (tests != 9)
|
||||
throw new RuntimeException("Not all cases ran, failing");
|
||||
}
|
||||
|
||||
private static void testReturnsZeroLengthArray() {
|
||||
for (Class<?> toTest : testData) {
|
||||
tests++;
|
||||
|
||||
AnnotatedType[] res = toTest.getAnnotatedInterfaces();
|
||||
|
||||
if (res == null) {
|
||||
failed++;
|
||||
System.out.println(toTest + ".class.getAnnotatedInterface() returns" +
|
||||
"'null' should zero length array");
|
||||
} else if (res.length != 0) {
|
||||
failed++;
|
||||
System.out.println(toTest + ".class.getAnnotatedInterfaces() returns: "
|
||||
+ Arrays.asList(res) + ", should be a zero length array of AnnotatedType");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface If {}
|
||||
|
||||
abstract static class Clz {}
|
||||
}
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Google LLC. 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 8066967 8198526
|
||||
* @summary Class.getAnnotatedSuperclass() does not correctly extract annotations
|
||||
*/
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class GetAnnotatedNestedSuperclass {
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface A {}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface B {}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface C {}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface D {}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface E {}
|
||||
|
||||
static class X<P1, P2, P3> {}
|
||||
|
||||
static class Y<P1, P2> extends @A X<@B P1, @C P2, @D Class<@E P1>> {}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AnnotatedType x = Y.class.getAnnotatedSuperclass();
|
||||
assertEquals(Arrays.toString(x.getAnnotations()), "[@GetAnnotatedNestedSuperclass.A()]");
|
||||
AnnotatedParameterizedType xpt = (AnnotatedParameterizedType) x;
|
||||
{
|
||||
AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[0];
|
||||
assertEquals(
|
||||
Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.B()]");
|
||||
}
|
||||
{
|
||||
AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[1];
|
||||
assertEquals(
|
||||
Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.C()]");
|
||||
}
|
||||
{
|
||||
AnnotatedType arg = xpt.getAnnotatedActualTypeArguments()[2];
|
||||
assertEquals(
|
||||
Arrays.toString(arg.getAnnotations()), "[@GetAnnotatedNestedSuperclass.D()]");
|
||||
AnnotatedType nestedArg =
|
||||
((AnnotatedParameterizedType) arg).getAnnotatedActualTypeArguments()[0];
|
||||
assertEquals(
|
||||
Arrays.toString(nestedArg.getAnnotations()),
|
||||
"[@GetAnnotatedNestedSuperclass.E()]");
|
||||
}
|
||||
}
|
||||
|
||||
private static void assertEquals(Object actual, Object expected) {
|
||||
if (!Objects.equals(expected, actual)) {
|
||||
throw new AssertionError("expected: " + expected + "; actual=" + actual);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2018, 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 8058595
|
||||
* @summary Test that AnnotatedType.getAnnotatedOwnerType() works as expected
|
||||
*
|
||||
* @library /test/lib
|
||||
* @build jdk.test.lib.Asserts
|
||||
* @run main GetAnnotatedOwnerType
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
public class GetAnnotatedOwnerType<Dummy> {
|
||||
public @TA("generic") GetAnnotatedOwnerType<String> . @TB("generic") Nested<Integer> genericField;
|
||||
public @TA("raw") GetAnnotatedOwnerType . @TB("raw") Nested rawField;
|
||||
public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("non-generic") Inner nonGeneric;
|
||||
public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("generic") InnerGeneric<String> innerGeneric;
|
||||
public @TA("non-generic") GetAnnotatedOwnerTypeAuxilliary . @TB("raw") InnerGeneric innerRaw;
|
||||
public GetAnnotatedOwnerTypeAuxilliary . @TB("non-generic") Nested nestedNonGeneric;
|
||||
public GetAnnotatedOwnerTypeAuxilliary . @TB("generic") NestedGeneric<String> nestedGeneric;
|
||||
public GetAnnotatedOwnerTypeAuxilliary . @TB("raw") NestedGeneric nestedRaw;
|
||||
public Object anonymous = new Object() {};
|
||||
public @TA("array") Dummy[] dummy;
|
||||
public @TA("wildcard") GetAnnotatedOwnerType<?> wildcard;
|
||||
public @TA("typevariable") Dummy tv;
|
||||
public @TA("bad") GetAnnotatedOwnerType<@TA("good") GetAnnotatedOwnerType<String> . @TB("tb") Nested<Integer> > typeArgument;
|
||||
public GetAnnotatedOwnerType< GetAnnotatedOwnerType<String> .
|
||||
B .
|
||||
C<Class<?>, ? extends @TA("complicated") Exception> .
|
||||
D<Number> > [] complicated;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testGeneric();
|
||||
testRaw();
|
||||
testNonGeneric();
|
||||
testInnerGeneric();
|
||||
testInnerRaw();
|
||||
testNestedNonGeneric();
|
||||
testNestedGeneric();
|
||||
testNestedRaw();
|
||||
|
||||
testLocalClass();
|
||||
testAnonymousClass();
|
||||
|
||||
testArray();
|
||||
testWildcard();
|
||||
testTypeParameter();
|
||||
|
||||
testTypeArgument();
|
||||
testComplicated();
|
||||
}
|
||||
|
||||
public static void testGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("genericField");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testRaw() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("rawField");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "raw");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testNonGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("nonGeneric");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "non-generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testInnerGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("innerGeneric");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testInnerRaw() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("innerRaw");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "non-generic");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testNestedNonGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("nestedNonGeneric");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "non-generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 0, "expecting no annotations, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testNestedGeneric() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("nestedGeneric");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "generic");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((ParameterizedType) f.getGenericType()).getOwnerType());
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 0, "expecting no annotations, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testNestedRaw() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("nestedRaw");
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = f.getAnnotatedType();
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "raw");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated, on the correct type
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getType(), ((Class<?>)f.getGenericType()).getEnclosingClass());
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 0, "expecting no annotations, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testLocalClass() throws Exception {
|
||||
class ALocalClass {}
|
||||
class OneMore {
|
||||
public @TA("null") ALocalClass c;
|
||||
}
|
||||
testNegative(OneMore.class.getField("c").getAnnotatedType(), "Local class should return null");
|
||||
}
|
||||
|
||||
public static void testAnonymousClass() throws Exception {
|
||||
testNegative(GetAnnotatedOwnerType.class.getField("anonymous").getAnnotatedType(),
|
||||
"Anonymous class should return null");
|
||||
}
|
||||
|
||||
public static void testArray() throws Exception {
|
||||
AnnotatedType t = GetAnnotatedOwnerType.class.getField("dummy").getAnnotatedType();
|
||||
Asserts.assertTrue((t instanceof AnnotatedArrayType),
|
||||
"Was expecting an AnnotatedArrayType " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
}
|
||||
|
||||
public static void testWildcard() throws Exception {
|
||||
AnnotatedType tt = GetAnnotatedOwnerType.class.getField("wildcard").getAnnotatedType();
|
||||
AnnotatedType t = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
|
||||
Asserts.assertTrue((t instanceof AnnotatedWildcardType),
|
||||
"Was expecting an AnnotatedWildcardType " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
}
|
||||
|
||||
public static void testTypeParameter() throws Exception {
|
||||
AnnotatedType t = GetAnnotatedOwnerType.class.getField("tv").getAnnotatedType();
|
||||
Asserts.assertTrue((t instanceof AnnotatedTypeVariable),
|
||||
"Was expecting an AnnotatedTypeVariable " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
}
|
||||
|
||||
public static void testTypeArgument() throws Exception {
|
||||
AnnotatedType tt = GetAnnotatedOwnerType.class.getField("typeArgument").getAnnotatedType();
|
||||
Asserts.assertEquals(tt.getAnnotation(TA.class).value(), "bad");
|
||||
Asserts.assertTrue(tt.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ tt.getAnnotations().length);
|
||||
|
||||
// make sure inner is correctly annotated
|
||||
AnnotatedType inner = ((AnnotatedParameterizedType)tt).getAnnotatedActualTypeArguments()[0];
|
||||
Asserts.assertEquals(inner.getAnnotation(TB.class).value(), "tb");
|
||||
Asserts.assertTrue(inner.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ inner.getAnnotations().length);
|
||||
|
||||
// make sure owner is correctly annotated
|
||||
AnnotatedType outer = inner.getAnnotatedOwnerType();
|
||||
Asserts.assertEquals(outer.getAnnotation(TA.class).value(), "good");
|
||||
Asserts.assertTrue(outer.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ outer.getAnnotations().length);
|
||||
}
|
||||
|
||||
public static void testComplicated() throws Exception {
|
||||
Field f = GetAnnotatedOwnerType.class.getField("complicated");
|
||||
|
||||
// Outermost level
|
||||
AnnotatedType t = f.getAnnotatedType();
|
||||
Asserts.assertTrue((t instanceof AnnotatedArrayType),
|
||||
"Was expecting an AnnotatedArrayType " + t);
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// Component type
|
||||
t = ((AnnotatedArrayType)t).getAnnotatedGenericComponentType();
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// Type arg GetAnnotatedOwnerType<String>...D<Number>
|
||||
t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[0];
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// C<Class<?>, ? extends ...>
|
||||
t = t.getAnnotatedOwnerType();
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// ? extends
|
||||
t = ((AnnotatedParameterizedType)t).getAnnotatedActualTypeArguments()[1];
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 0, "expecting zero annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
|
||||
// @TA("complicated") Exception
|
||||
t = ((AnnotatedWildcardType)t).getAnnotatedUpperBounds()[0];
|
||||
testNegative(t, "" + t + " should not have an annotated owner type");
|
||||
Asserts.assertEquals(t.getAnnotation(TA.class).value(), "complicated");
|
||||
Asserts.assertTrue(t.getAnnotations().length == 1, "expecting one (1) annotation, got: "
|
||||
+ t.getAnnotations().length);
|
||||
}
|
||||
|
||||
private static void testNegative(AnnotatedType t, String msg) {
|
||||
Asserts.assertNull(t.getAnnotatedOwnerType(), msg);
|
||||
}
|
||||
|
||||
public class Nested<AlsoDummy> {}
|
||||
public class B {
|
||||
public class C<R, S> {
|
||||
public class D<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TA {
|
||||
String value();
|
||||
}
|
||||
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TB {
|
||||
String value();
|
||||
}
|
||||
}
|
||||
|
||||
class GetAnnotatedOwnerTypeAuxilliary {
|
||||
class Inner {}
|
||||
|
||||
class InnerGeneric<Dummy> {}
|
||||
|
||||
static class Nested {}
|
||||
|
||||
static class NestedGeneric<Dummy> {}
|
||||
}
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2014, 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 8024915 8044629 8256693
|
||||
*/
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class GetAnnotatedReceiverType {
|
||||
public void method() {}
|
||||
public void method0(GetAnnotatedReceiverType this) {}
|
||||
public static void method4() {}
|
||||
|
||||
class Inner0 {
|
||||
public Inner0() {}
|
||||
}
|
||||
|
||||
class Inner1 {
|
||||
public Inner1(GetAnnotatedReceiverType GetAnnotatedReceiverType.this) {}
|
||||
}
|
||||
|
||||
public static class Nested {
|
||||
public Nested() {}
|
||||
|
||||
public class NestedInner {
|
||||
public NestedInner() { }
|
||||
|
||||
public Class<?> getLocalClass () {
|
||||
class NestedInnerLocal { public NestedInnerLocal() {} }
|
||||
return NestedInnerLocal.class;
|
||||
}
|
||||
|
||||
public Class<?> getAnonymousClass() {
|
||||
return new Object() {}.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Inner2 {
|
||||
public Inner2() { }
|
||||
public void innerMethod2(GetAnnotatedReceiverType.Inner2 this) {}
|
||||
|
||||
public class Inner3 {
|
||||
public Inner3() { }
|
||||
public void innerMethod3(GetAnnotatedReceiverType.Inner2.Inner3 this) {}
|
||||
|
||||
public class Inner7<T> {
|
||||
public void innerMethod7(GetAnnotatedReceiverType.Inner2.Inner3.Inner7<T> this) {}
|
||||
}
|
||||
|
||||
public Class<?> getLocalClass () {
|
||||
class InnerLocal { public InnerLocal() {} }
|
||||
return InnerLocal.class;
|
||||
}
|
||||
|
||||
public Class<?> getAnonymousClass() {
|
||||
return new Object() {}.getClass();
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> getLocalClass () {
|
||||
class InnerLocal { public InnerLocal() {} }
|
||||
return InnerLocal.class;
|
||||
}
|
||||
|
||||
public Class<?> getAnonymousClass() {
|
||||
return new Object() {}.getClass();
|
||||
}
|
||||
}
|
||||
|
||||
public class Inner4<T> {
|
||||
public Inner4(GetAnnotatedReceiverType GetAnnotatedReceiverType.this) {}
|
||||
public void innerMethod4(GetAnnotatedReceiverType.Inner4<T> this) {}
|
||||
|
||||
public class Inner5 {
|
||||
public Inner5(GetAnnotatedReceiverType.Inner4<T> GetAnnotatedReceiverType.Inner4.this) {}
|
||||
public void innerMethod5(GetAnnotatedReceiverType.Inner4<T>.Inner5 this) {}
|
||||
|
||||
public class Inner6 {
|
||||
public Inner6(GetAnnotatedReceiverType.Inner4<T>.Inner5 GetAnnotatedReceiverType.Inner4.Inner5.this) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int failures = 0;
|
||||
private static int tests = 0;
|
||||
private static final int EXPECTED_TEST_CASES = 25;
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method"),
|
||||
"getAnnotatedReceiverType for \"method\" should return an empty AnnotatedType");
|
||||
checkEmptyAT(Inner0.class.getConstructor(GetAnnotatedReceiverType.class),
|
||||
"getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType");
|
||||
|
||||
checkEmptyAT(GetAnnotatedReceiverType.class.getMethod("method0"),
|
||||
"getAnnotatedReceiverType for \"method0\" should return an empty AnnotatedType");
|
||||
checkEmptyAT(Inner1.class.getConstructor(GetAnnotatedReceiverType.class),
|
||||
"getAnnotatedReceiverType for a ctor with a \"this\" should return an empty AnnotatedType");
|
||||
|
||||
checkNull(GetAnnotatedReceiverType.class.getMethod("method4"),
|
||||
"getAnnotatedReceiverType() on a static method should return null");
|
||||
|
||||
// More nested, inner, local and anonymous classes
|
||||
Nested nested = new Nested();
|
||||
Nested.NestedInner instance = nested.new NestedInner();
|
||||
checkNull(nested.getClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for a static class should return null");
|
||||
checkEmptyAT(instance.getClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType");
|
||||
checkNull(instance.getLocalClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for a local class should return null");
|
||||
checkNull(instance.getAnonymousClass().getDeclaredConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for an anonymous class should return null");
|
||||
|
||||
GetAnnotatedReceiverType outer = new GetAnnotatedReceiverType();
|
||||
Inner2 instance2 = outer.new Inner2();
|
||||
checkEmptyAT(instance2.getClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType");
|
||||
checkNull(instance2.getLocalClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for a local class should return null");
|
||||
checkNull(instance2.getAnonymousClass().getDeclaredConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for an anonymous class should return null");
|
||||
|
||||
Inner2.Inner3 instance3 = instance2.new Inner3();
|
||||
checkEmptyAT(instance3.getClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType for a ctor without a \"this\" should return an empty AnnotatedType");
|
||||
checkNull(instance3.getLocalClass().getConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for a local class should return null");
|
||||
checkNull(instance3.getAnonymousClass().getDeclaredConstructors()[0],
|
||||
"getAnnotatedReceiverType() on a constructor for an anonymous class should return null");
|
||||
|
||||
Inner4<?> instance4 = outer.new Inner4<String>();
|
||||
Inner4<?>.Inner5 instance5 = instance4.new Inner5();
|
||||
Inner4<?>.Inner5.Inner6 instance6 = instance5.new Inner6();
|
||||
|
||||
checkAnnotatedReceiverType(instance4.getClass().getConstructors()[0], false,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this constructor should be");
|
||||
checkAnnotatedReceiverType(instance5.getClass().getConstructors()[0], true,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this constructor should be");
|
||||
checkAnnotatedReceiverType(instance6.getClass().getConstructors()[0], true,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this constructor should be");
|
||||
checkAnnotatedReceiverType(outer.getClass().getMethod("method0"), false,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this method should be");
|
||||
checkAnnotatedReceiverType(instance4.getClass().getMethod("innerMethod4"), true,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this method should be");
|
||||
checkAnnotatedReceiverType(instance5.getClass().getMethod("innerMethod5"), true,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this method should be");
|
||||
checkAnnotatedReceiverType(instance2.getClass().getMethod("innerMethod2"), false,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this method should be");
|
||||
checkAnnotatedReceiverType(instance3.getClass().getMethod("innerMethod3"), false,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this method should be");
|
||||
|
||||
Inner2.Inner3.Inner7<?> instance7 = instance3.new Inner7<String>();
|
||||
checkAnnotatedReceiverType(instance7.getClass().getMethod("innerMethod7"), true,
|
||||
"The type of .getAnnotatedReceiverType().getType() for this method should be");
|
||||
recursiveCheckAnnotatedOwnerTypes(instance7.getClass().getMethod("innerMethod7").getAnnotatedReceiverType());
|
||||
|
||||
if (failures != 0)
|
||||
throw new RuntimeException("Test failed, see log for details");
|
||||
else if (tests != EXPECTED_TEST_CASES)
|
||||
throw new RuntimeException("Not all cases ran, failing");
|
||||
}
|
||||
|
||||
private static void checkNull(Executable e, String msg) {
|
||||
AnnotatedType a = e.getAnnotatedReceiverType();
|
||||
if (a != null) {
|
||||
failures++;
|
||||
System.err.println(msg + ": " + e);
|
||||
}
|
||||
tests++;
|
||||
}
|
||||
|
||||
private static void checkEmptyAT(Executable e, String msg) {
|
||||
AnnotatedType a = e.getAnnotatedReceiverType();
|
||||
if (a.getAnnotations().length != 0) {
|
||||
failures++;
|
||||
System.err.print(msg + ": " + e);
|
||||
}
|
||||
tests++;
|
||||
}
|
||||
|
||||
private static void checkAnnotatedReceiverType(Executable e, boolean shouldBeParameterized, String msg) {
|
||||
Type t = e.getAnnotatedReceiverType().getType();
|
||||
if (shouldBeParameterized != (t instanceof ParameterizedType)) {
|
||||
failures++;
|
||||
System.err.println(e + ", " + msg + " " + (shouldBeParameterized ? "ParameterizedType" : "Class") + ", found: " + t.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
// Test we can get the potentially empty annotated actual type arguments array
|
||||
if (shouldBeParameterized) {
|
||||
try {
|
||||
ParameterizedType t1 = (ParameterizedType)t;
|
||||
AnnotatedParameterizedType at1 = (AnnotatedParameterizedType)e.getAnnotatedReceiverType();
|
||||
|
||||
if (t1.getActualTypeArguments().length != at1.getAnnotatedActualTypeArguments().length) {
|
||||
System.err.println(t1 + "'s actual type arguments can't match " + at1);
|
||||
failures++;
|
||||
}
|
||||
} catch (ClassCastException cce) {
|
||||
System.err.println("Couldn't get potentially empty actual type arguments: " + cce.getMessage());
|
||||
failures++;
|
||||
}
|
||||
}
|
||||
tests++;
|
||||
}
|
||||
|
||||
private static void recursiveCheckAnnotatedOwnerTypes(AnnotatedType t) {
|
||||
AnnotatedType check = t.getAnnotatedOwnerType();
|
||||
do {
|
||||
if (!(check.getType() instanceof Class<?>)) {
|
||||
failures++;
|
||||
System.err.println("Expecting only instances of Class returned for .getType() found " + check.getType().getClass().getSimpleName());
|
||||
}
|
||||
check = check.getAnnotatedOwnerType();
|
||||
} while (check != null);
|
||||
tests++;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 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 8022343 8007072
|
||||
* @summary Test Class.getAnnotatedSuperclass() returns null/non-null
|
||||
* AnnotatedType as specified
|
||||
*/
|
||||
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class GetAnnotatedSuperclass {
|
||||
private static final Class<?>[] nullTestData = {
|
||||
Object.class,
|
||||
If.class,
|
||||
Object[].class,
|
||||
void.class,
|
||||
int.class,
|
||||
};
|
||||
|
||||
private static final Class<?>[] nonNullTestData = {
|
||||
Class.class,
|
||||
GetAnnotatedSuperclass.class,
|
||||
(new If() {}).getClass(),
|
||||
(new Clz() {}).getClass(),
|
||||
(new Object() {}).getClass(),
|
||||
};
|
||||
|
||||
private static int failed = 0;
|
||||
private static int tests = 0;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
testReturnsNull();
|
||||
testReturnsEmptyAT();
|
||||
|
||||
if (failed != 0)
|
||||
throw new RuntimeException("Test failed, check log for details");
|
||||
if (tests != 10)
|
||||
throw new RuntimeException("Not all cases ran, failing");
|
||||
}
|
||||
|
||||
private static void testReturnsNull() {
|
||||
for (Class<?> toTest : nullTestData) {
|
||||
tests++;
|
||||
|
||||
Object res = toTest.getAnnotatedSuperclass();
|
||||
|
||||
if (res != null) {
|
||||
failed++;
|
||||
System.out.println(toTest + ".getAnnotatedSuperclass() returns: "
|
||||
+ res + ", should be null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testReturnsEmptyAT() {
|
||||
for (Class<?> toTest : nonNullTestData) {
|
||||
tests++;
|
||||
|
||||
AnnotatedType res = toTest.getAnnotatedSuperclass();
|
||||
|
||||
if (res == null) {
|
||||
failed++;
|
||||
System.out.println(toTest + ".getAnnotatedSuperclass() returns 'null' should be non-null");
|
||||
} else if (res.getAnnotations().length != 0) {
|
||||
failed++;
|
||||
System.out.println(toTest + ".getAnnotatedSuperclass() returns: "
|
||||
+ Arrays.asList(res.getAnnotations()) + ", should be an empty AnnotatedType");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface If {}
|
||||
|
||||
abstract static class Clz {}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface MissingAnnotation { }
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright (c) 2016, 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 8152174
|
||||
* @summary Verify that a missing class file for a type use annotation doesn't cause a NPE when attempting to read the annotation.
|
||||
* @compile NoNpeOnMissingAnnotation.java MissingAnnotation.java
|
||||
* @run main NoNpeOnMissingAnnotation
|
||||
* @clean MissingAnnotation
|
||||
* @run main NoNpeOnMissingAnnotation
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
public class NoNpeOnMissingAnnotation {
|
||||
public static void main(String... args) throws Exception {
|
||||
System.out.println(NoNpeOnMissingAnnotation.class.
|
||||
getDeclaredMethod("foo").
|
||||
getAnnotatedReturnType());
|
||||
}
|
||||
|
||||
@MissingAnnotation Object foo() { return null; }
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 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 8202469
|
||||
* @summary Test adjustment of type bound index if no explicit class bound is defined
|
||||
* @compile ParameterizedBoundIndex.java
|
||||
* @run main ParameterizedBoundIndex
|
||||
*/
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* According to JVMS 4.3.4, the first bound of a parameterized type is
|
||||
* taken to be Object, if no explicit class bound is specified. As a
|
||||
* consequence, the first interface's bound is always 1, independently
|
||||
* of an explicit class bound.
|
||||
*
|
||||
* This test investigates if this mismatch between explicit and actual
|
||||
* type bound index is accounted for.
|
||||
*/
|
||||
public class ParameterizedBoundIndex {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
List<Class<?>> failed = new ArrayList<>();
|
||||
|
||||
if (!TypeClassBound.class.getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(TypeClassBound.class);
|
||||
}
|
||||
if (!TypeInterfaceBound.class.getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(TypeInterfaceBound.class);
|
||||
}
|
||||
if (!TypeParameterizedInterfaceBound.class.getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(TypeParameterizedInterfaceBound.class);
|
||||
}
|
||||
if (!TypeParameterizedClassBound.class.getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(TypeParameterizedClassBound.class);
|
||||
}
|
||||
if (!TypeVariableBound.class.getTypeParameters()[1].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(TypeVariableBound.class);
|
||||
}
|
||||
|
||||
if (!MethodClassBound.class.getDeclaredMethod("m").getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(MethodClassBound.class);
|
||||
}
|
||||
if (!MethodInterfaceBound.class.getDeclaredMethod("m").getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(MethodInterfaceBound.class);
|
||||
}
|
||||
if (!MethodParameterizedInterfaceBound.class.getDeclaredMethod("m").getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(MethodParameterizedInterfaceBound.class);
|
||||
}
|
||||
if (!MethodParameterizedClassBound.class.getDeclaredMethod("m").getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(MethodParameterizedClassBound.class);
|
||||
}
|
||||
if (!MethodVariableBound.class.getDeclaredMethod("m").getTypeParameters()[1].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(MethodVariableBound.class);
|
||||
}
|
||||
|
||||
if (!ConstructorClassBound.class.getDeclaredConstructor().getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(ConstructorClassBound.class);
|
||||
}
|
||||
if (!ConstructorInterfaceBound.class.getDeclaredConstructor().getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(ConstructorInterfaceBound.class);
|
||||
}
|
||||
if (!ConstructorParameterizedInterfaceBound.class.getDeclaredConstructor().getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(ConstructorParameterizedInterfaceBound.class);
|
||||
}
|
||||
if (!ConstructorParameterizedClassBound.class.getDeclaredConstructor().getTypeParameters()[0].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(ConstructorParameterizedClassBound.class);
|
||||
}
|
||||
if (!ConstructorVariableBound.class.getDeclaredConstructor().getTypeParameters()[1].getAnnotatedBounds()[0].isAnnotationPresent(TypeAnnotation.class)) {
|
||||
failed.add(ConstructorVariableBound.class);
|
||||
}
|
||||
|
||||
if (!failed.isEmpty()) {
|
||||
throw new RuntimeException("Failed: " + failed);
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation { }
|
||||
|
||||
static class TypeClassBound<T extends @TypeAnnotation Void> { }
|
||||
static class TypeInterfaceBound<T extends @TypeAnnotation Runnable> { }
|
||||
static class TypeParameterizedInterfaceBound<T extends @TypeAnnotation List<?>> { }
|
||||
static class TypeParameterizedClassBound<T extends @TypeAnnotation ArrayList<?>> { }
|
||||
static class TypeVariableBound<T, S extends @TypeAnnotation T> { }
|
||||
|
||||
static class MethodClassBound<T extends @TypeAnnotation Void> {
|
||||
<T extends @TypeAnnotation Void> void m() { }
|
||||
}
|
||||
static class MethodInterfaceBound {
|
||||
<T extends @TypeAnnotation Runnable> void m() { }
|
||||
}
|
||||
static class MethodParameterizedInterfaceBound<T extends @TypeAnnotation List<?>> {
|
||||
<T extends @TypeAnnotation List<?>> void m() { }
|
||||
}
|
||||
static class MethodParameterizedClassBound {
|
||||
<T extends @TypeAnnotation ArrayList<?>> void m() { }
|
||||
}
|
||||
static class MethodVariableBound<T, S extends @TypeAnnotation T> {
|
||||
<T, S extends @TypeAnnotation T> void m() { }
|
||||
}
|
||||
|
||||
static class ConstructorClassBound<T extends @TypeAnnotation Void> {
|
||||
<T extends @TypeAnnotation Void> ConstructorClassBound() { }
|
||||
}
|
||||
static class ConstructorInterfaceBound {
|
||||
<T extends @TypeAnnotation Runnable> ConstructorInterfaceBound() { }
|
||||
}
|
||||
static class ConstructorParameterizedInterfaceBound<T extends @TypeAnnotation List<?>> {
|
||||
<T extends @TypeAnnotation List<?>> ConstructorParameterizedInterfaceBound() { }
|
||||
}
|
||||
static class ConstructorParameterizedClassBound {
|
||||
<T extends @TypeAnnotation ArrayList<?>> ConstructorParameterizedClassBound() { }
|
||||
}
|
||||
static class ConstructorVariableBound<T, S extends @TypeAnnotation T> {
|
||||
<T, S extends @TypeAnnotation T> ConstructorVariableBound() { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* Copyright (c) 2017, 2022, 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(1)"})
|
||||
public class NestedClass1 {
|
||||
public NestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[[], [], []]")
|
||||
@ExpectedParameterTypeAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(2)",
|
||||
"null"})
|
||||
public class NestedClass2 {
|
||||
public NestedClass2(@MarkerTypeAnnotation(2) int parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[[], [], []]")
|
||||
@ExpectedParameterTypeAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(3)",
|
||||
"null"})
|
||||
public class NestedClass3 {
|
||||
public <P> NestedClass3(@MarkerTypeAnnotation(3) P parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[[], [], []]")
|
||||
@ExpectedParameterTypeAnnotations({
|
||||
"null",
|
||||
"@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(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(1)"})
|
||||
public static class StaticNestedClass1 {
|
||||
public StaticNestedClass1(@MarkerTypeAnnotation(1) int parameter) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[[], []]")
|
||||
@ExpectedParameterTypeAnnotations({
|
||||
"@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(2)",
|
||||
"null"})
|
||||
public static class StaticNestedClass2 {
|
||||
public StaticNestedClass2(@MarkerTypeAnnotation(2) int parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[[], []]")
|
||||
@ExpectedParameterTypeAnnotations({
|
||||
"@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(3)",
|
||||
"null"})
|
||||
public static class StaticNestedClass3 {
|
||||
public <P> StaticNestedClass3(@MarkerTypeAnnotation(3) P parameter1,
|
||||
int parameter2) {}
|
||||
}
|
||||
|
||||
@ExpectedGetParameterAnnotations("[[], []]")
|
||||
@ExpectedParameterTypeAnnotations({
|
||||
"@TestConstructorParameterTypeAnnotations.MarkerTypeAnnotation(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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,284 @@
|
|||
/*
|
||||
* Copyright (c) 2014, 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 8039916
|
||||
* @summary Test that a call to getType() on an AnnotatedType returned from an
|
||||
* Executable.getAnnotated* returns the same type as the corresponding
|
||||
* Executable.getGeneric* call.
|
||||
* @run testng TestExecutableGetAnnotatedType
|
||||
*/
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class TestExecutableGetAnnotatedType {
|
||||
@Test(dataProvider = "genericExecutableData")
|
||||
public void testGenericMethodExceptions(Executable e) throws Exception {
|
||||
testExceptions(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "executableData")
|
||||
public void testMethodExceptions(Executable e) throws Exception {
|
||||
testExceptions(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "genericExecutableData")
|
||||
public void testGenericMethodParameterTypes(Executable e) throws Exception {
|
||||
testMethodParameters(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "executableData")
|
||||
public void testMethodParameterTypes(Executable e) throws Exception {
|
||||
testMethodParameters(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "genericExecutableData")
|
||||
public void testGenericParameterTypes(Executable e) throws Exception {
|
||||
testParameters(e.getParameters());
|
||||
}
|
||||
|
||||
@Test(dataProvider = "executableData")
|
||||
public void testParameterTypes(Executable e) throws Exception {
|
||||
testParameters(e.getParameters());
|
||||
}
|
||||
|
||||
@Test(dataProvider = "genericMethodData")
|
||||
public void testGenericReceiverType(Executable e) throws Exception {
|
||||
testParameterizedReceiverType0(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "methodData")
|
||||
public void testReceiverType(Executable e) throws Exception {
|
||||
testReceiverType0(e);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "genericMethodData")
|
||||
public void testGenericMethodReturnType(Object o) throws Exception {
|
||||
// testng gets confused if the param to this method has type Method
|
||||
Method m = (Method)o;
|
||||
testReturnType(m);
|
||||
}
|
||||
|
||||
@Test(dataProvider = "methodData")
|
||||
public void testMethodReturnType(Object o) throws Exception {
|
||||
// testng gets confused if the param to this method has type Method
|
||||
Method m = (Method)o;
|
||||
testReturnType(m);
|
||||
}
|
||||
|
||||
private void testExceptions(Executable e) {
|
||||
Type[] ts = e.getGenericExceptionTypes();
|
||||
AnnotatedType[] ats = e.getAnnotatedExceptionTypes();
|
||||
assertEquals(ts.length, ats.length);
|
||||
|
||||
for (int i = 0; i < ts.length; i++) {
|
||||
Type t = ts[i];
|
||||
AnnotatedType at = ats[i];
|
||||
assertSame(at.getType(), t, e.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void testMethodParameters(Executable e) {
|
||||
Type[] ts = e.getGenericParameterTypes();
|
||||
AnnotatedType[] ats = e.getAnnotatedParameterTypes();
|
||||
assertEquals(ts.length, ats.length);
|
||||
|
||||
for (int i = 0; i < ts.length; i++) {
|
||||
Type t = ts[i];
|
||||
AnnotatedType at = ats[i];
|
||||
assertSame(at.getType(), t, e.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void testParameters(Parameter[] params) {
|
||||
for (Parameter p : params) {
|
||||
Type t = p.getParameterizedType();
|
||||
AnnotatedType at = p.getAnnotatedType();
|
||||
assertSame(at.getType(), t, p.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
private void testReceiverType0(Executable e) {
|
||||
if (Modifier.isStatic(e.getModifiers()))
|
||||
assertNull(e.getAnnotatedReceiverType());
|
||||
else
|
||||
assertSame(e.getAnnotatedReceiverType().getType(), e.getDeclaringClass());
|
||||
}
|
||||
|
||||
private void testParameterizedReceiverType0(Executable e) {
|
||||
if (Modifier.isStatic(e.getModifiers()))
|
||||
assertNull(e.getAnnotatedReceiverType());
|
||||
else {
|
||||
assertTrue(e.getAnnotatedReceiverType().getType() instanceof ParameterizedType);
|
||||
assertSame(((ParameterizedType) e.getAnnotatedReceiverType().getType()).getRawType(), e.getDeclaringClass());
|
||||
}
|
||||
}
|
||||
|
||||
private void testReturnType(Method m) {
|
||||
Type t = m.getGenericReturnType();
|
||||
AnnotatedType at = m.getAnnotatedReturnType();
|
||||
assertSame(at.getType(), t, m.toString() + ": T: " + t + ", AT: " + at + ", AT.getType(): " + at.getType() + "\n");
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] methodData() throws Exception {
|
||||
return filterData(Arrays.stream(Methods1.class.getMethods()), Methods1.class)
|
||||
.toArray(new Object[0][0]);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] genericMethodData() throws Exception {
|
||||
return filterData(Arrays.stream(GenericMethods1.class.getMethods()), GenericMethods1.class)
|
||||
.toArray(new Object[0][0]);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] executableData() throws Exception {
|
||||
@SuppressWarnings("raw")
|
||||
List l = filterData(Arrays.stream(Methods1.class.getMethods()), Methods1.class);
|
||||
l.addAll(filterData(Arrays.stream(Methods1.class.getConstructors()), Methods1.class));
|
||||
l.addAll(filterData(Arrays.stream(Ctors1.class.getConstructors()), Ctors1.class));
|
||||
return ((List<Object[][]>)l).toArray(new Object[0][0]);
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Object[][] genericExecutableData() throws Exception {
|
||||
@SuppressWarnings("raw")
|
||||
List l = filterData(Arrays.stream(GenericMethods1.class.getMethods()), GenericMethods1.class);
|
||||
l.addAll(filterData(Arrays.stream(GenericMethods1.class.getConstructors()), GenericMethods1.class));
|
||||
l.addAll(filterData(Arrays.stream(GenericCtors1.class.getConstructors()), GenericCtors1.class));
|
||||
return ((List<Object[][]>)l).toArray(new Object[0][0]);
|
||||
}
|
||||
|
||||
private List<?> filterData(Stream<? extends Executable> l, Class<?> c) {
|
||||
return l.filter(m -> (m.getDeclaringClass() == c)) // remove object methods
|
||||
.map(m -> { Object[] o = new Object[1]; o[0] = m; return o; })
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface TA {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface TB {}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
public @interface TC {}
|
||||
|
||||
public static class Methods1 {
|
||||
public static void m1() throws Error, RuntimeException {;}
|
||||
public static long m2(int a, double b) throws Error, RuntimeException { return 0L; }
|
||||
public static Object m3(String s, List l) throws Error, RuntimeException { return null; }
|
||||
public static Object m4(String s, List<String> l) { return null; }
|
||||
public static Object m4(String s, List<String> l, boolean ... b){ return null; }
|
||||
|
||||
public static void m10() throws @TA Error, @TB @TC RuntimeException {;}
|
||||
public static @TB long m20(@TC int a, @TA double b) throws @TA Error, @TB @TC RuntimeException { return 0L; }
|
||||
public static @TC Object m30(@TA String s, @TB List l) throws @TA Error, @TB @TC RuntimeException { return null; }
|
||||
public static @TA Object m40(@TB String s, @TC List<@TA String> l) { return null; }
|
||||
public static @TA Object m40(@TB String s, @TC List<@TA String> l, @TB boolean ... b) { return null; }
|
||||
|
||||
public Methods1(int a, double b) {}
|
||||
public Methods1(String s, List<String> l, boolean ... b) {}
|
||||
public Methods1(@TC long a, @TA float b) {}
|
||||
public Methods1(@TA int i, @TB String s, @TC List<@TA String> l, @TB boolean ... b) {}
|
||||
}
|
||||
|
||||
// test default ctor
|
||||
public static class Ctors1 {
|
||||
}
|
||||
|
||||
public static class GenericMethods1<E> {
|
||||
public E m1(E e, Object o) throws Error, RuntimeException { return null; }
|
||||
public E m2(List<? extends List> e, int i) throws Error, RuntimeException { return null; }
|
||||
public E m3(double d, List<E> e) throws Error, RuntimeException { return null; }
|
||||
public <E extends List> E m4(byte[] b, GenericMethods1<? extends E> e) { return null; }
|
||||
public <E extends List> E m5(GenericMethods1<? super Number> e) { return null; }
|
||||
public <E extends List & Cloneable> E m6(char c, E e) { return null; }
|
||||
public <E extends List & Cloneable> E m7(char c, E e, byte ... b) { return null; }
|
||||
|
||||
public static <M> M n1(M e) { return null; }
|
||||
public static <M> M n2(List<? extends List> e) { return null; }
|
||||
public static <M extends RuntimeException> M n3(List<M> e) throws Error, M { return null; }
|
||||
public static <M extends Number> M n4(GenericMethods1<? extends M> e) throws Error, RuntimeException { return null; }
|
||||
public static <M extends Object> M n5(GenericMethods1<? super Number> e) { return null; }
|
||||
public static <M extends List & Cloneable> M n6(M e) { return null; }
|
||||
|
||||
public <M> E o1(E e) { return null; }
|
||||
public <M> E o2(List<? extends List> e) { return null; }
|
||||
public <M extends Error, N extends RuntimeException> E o3(GenericMethods1<E> this, List<E> e) throws M, N { return null; }
|
||||
public <M extends Number> E o4(GenericMethods1<? extends E> e) throws Error, RuntimeException { return null; }
|
||||
public <M extends Object> E o5(GenericMethods1<? super Number> e) { return null; }
|
||||
public <M extends List & Cloneable> E o6(E e) { return null; }
|
||||
|
||||
|
||||
// with annotations
|
||||
public @TA E m10(E e, @TC Object o) throws @TA Error, @TB @TC RuntimeException { return null; }
|
||||
public @TB E m20(@TA List<@TA ? extends @TA List> e, @TC int i) throws @TA Error, @TB @TC RuntimeException { return null; }
|
||||
public @TB E m30(@TC double d, List<E> e) throws @TA Error, @TB @TC RuntimeException { return null; }
|
||||
public <@TA E extends @TA List> @TA E m40(@TA byte @TB [] b, GenericMethods1<@TA ? extends E> e) { return null; }
|
||||
public <@TB E extends @TB List> E m50(@TA GenericMethods1<? super Number> e) { return null; }
|
||||
public <@TB E extends @TA List & Cloneable> E m60(@TC char c, E e) { return null; }
|
||||
public <@TB E extends @TA List & Cloneable> E m70(@TC char c, E e, @TA @TB byte ... b) { return null; }
|
||||
|
||||
public static <@TA M> @TA M n10(M e) { return null; }
|
||||
public static <@TA @TB @TC M> M n20(List<@TA ? extends List> e) { return null; }
|
||||
@TA @TB @TC public static <M extends RuntimeException> M n30(List<@TB M> e) throws @TA Error, @TB @TC M { return null; }
|
||||
public static <@TC M extends Number> M n40(GenericMethods1<? extends @TA M> e) throws @TA Error, @TB @TC RuntimeException { return null; }
|
||||
@TA public static <M extends @TB Object> M n50(GenericMethods1<? super Number> e) { return null; }
|
||||
public static <@TA M extends @TB List & @TC @TB Cloneable> M n60(M e) { return null; }
|
||||
|
||||
public <@TC M> E o10(@TA E e) { return null; }
|
||||
public <M> @TA E o20(@TB List<@TB ? extends @TB List> e) { return null; }
|
||||
@TC public <M extends Error, N extends RuntimeException> @TB E o30(@TA @TB @TC GenericMethods1<E> this, List<E> e) throws @TA M, @TB @TC N { return null; }
|
||||
public <@TA M extends Number> E o40(GenericMethods1<? extends @TA E> e) throws @TA Error, @TB @TC RuntimeException { return null; }
|
||||
public <M extends @TA Object> E o50(GenericMethods1<@TA ? super Number> e) { return null; }
|
||||
public <@TA M extends @TB List & @TC Cloneable> E o60(@TA E e) { return null; }
|
||||
|
||||
|
||||
// ctors
|
||||
public GenericMethods1(List<? extends List> e, int i) throws Error, RuntimeException { }
|
||||
public <E extends List & Cloneable> GenericMethods1(char c, E e, byte ... b) { }
|
||||
@TC public <M extends Error, N extends RuntimeException> GenericMethods1(List<@TC E> e) throws @TA M, @TB @TC N { }
|
||||
public <@TA M extends @TB List & @TC Cloneable> GenericMethods1(@TA E e, @TB M m) throws @TA Exception { }
|
||||
public <@TA M extends @TB List & @TC Cloneable> GenericMethods1(@TA E e, @TB M m, @TC byte ... b) throws Exception { }
|
||||
}
|
||||
|
||||
// test default ctor
|
||||
public static class GenericCtors1<T> {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,507 @@
|
|||
/*
|
||||
* Copyright (c) 2018, 2022, 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 8058202 8212081 8224012
|
||||
* @summary Test java.lang.Object methods on AnnotatedType objects.
|
||||
*/
|
||||
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import java.util.regex.*;
|
||||
|
||||
/**
|
||||
* Test toString, equals, and hashCode on various AnnotatedType objects.
|
||||
*/
|
||||
|
||||
public class TestObjectMethods {
|
||||
private static int errors = 0;
|
||||
|
||||
/*
|
||||
* There are various subtypes of AnnotatedType implementations:
|
||||
*
|
||||
* AnnotatedType
|
||||
* AnnotatedArrayType
|
||||
* AnnotatedParameterizedType
|
||||
* AnnotatedTypeVariable
|
||||
* AnnotatedWildcardType
|
||||
*
|
||||
* The implementations of each these implementations are
|
||||
* examined. Wildcards don't appear as top-level types and need to
|
||||
* be extracted from bounds.
|
||||
*
|
||||
* AnnotatedTypes with and without annotations are examined as
|
||||
* well.
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
Class<?>[] testClasses = {TypeHost.class, AnnotatedTypeHost.class};
|
||||
|
||||
for (Class<?> clazz : testClasses) {
|
||||
testEqualsReflexivity(clazz);
|
||||
testEquals(clazz);
|
||||
}
|
||||
|
||||
testToString(TypeHost.class);
|
||||
testToString(AnnotatedTypeHost.class);
|
||||
|
||||
testAnnotationsMatterForEquals(TypeHost.class, AnnotatedTypeHost.class);
|
||||
|
||||
testGetAnnotations(TypeHost.class, false);
|
||||
testGetAnnotations(AnnotatedTypeHost.class, true);
|
||||
|
||||
testWildcards();
|
||||
|
||||
testFbounds();
|
||||
|
||||
if (errors > 0) {
|
||||
throw new RuntimeException(errors + " errors");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For non-array types, verify toString version of the annotated
|
||||
* type ends with the same string as the generic type.
|
||||
*/
|
||||
static void testToString(Class<?> clazz) {
|
||||
System.err.println("Testing toString on methods of class " + clazz.getName());
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
for (Method m : methods) {
|
||||
// Expected information about the type annotations stored
|
||||
// in a *declaration* annotation.
|
||||
AnnotTypeInfo annotTypeInfo = m.getAnnotation(AnnotTypeInfo.class);
|
||||
int expectedAnnotCount = annotTypeInfo.count();
|
||||
Relation relation = annotTypeInfo.relation();
|
||||
|
||||
AnnotatedType annotType = m.getAnnotatedReturnType();
|
||||
String annotTypeString = annotType.toString();
|
||||
|
||||
Type type = m.getGenericReturnType();
|
||||
String typeString = (type instanceof Class) ?
|
||||
type.getTypeName() :
|
||||
type.toString();
|
||||
|
||||
boolean isArray = annotType instanceof AnnotatedArrayType;
|
||||
boolean isVoid = "void".equals(typeString);
|
||||
|
||||
boolean valid;
|
||||
|
||||
switch(relation) {
|
||||
case EQUAL:
|
||||
valid = annotTypeString.equals(typeString);
|
||||
break;
|
||||
|
||||
case POSTFIX:
|
||||
valid = annotTypeString.endsWith(typeString) &&
|
||||
!annotTypeString.startsWith(typeString);
|
||||
break;
|
||||
|
||||
case STRIPPED:
|
||||
String stripped = annotationRegex.matcher(annotTypeString).replaceAll("");
|
||||
valid = typeString.replace(" ", "").equals(stripped.replace(" ", ""));
|
||||
break;
|
||||
|
||||
case ARRAY:
|
||||
// Find final non-array component type and gets its name.
|
||||
typeString = null;
|
||||
|
||||
AnnotatedType componentType = annotType;
|
||||
while (componentType instanceof AnnotatedArrayType) {
|
||||
AnnotatedArrayType annotatedArrayType = (AnnotatedArrayType) componentType;
|
||||
componentType = annotatedArrayType.getAnnotatedGenericComponentType();
|
||||
}
|
||||
|
||||
String componentName = componentType.getType().getTypeName();
|
||||
valid = annotTypeString.contains(componentName);
|
||||
break;
|
||||
|
||||
case OTHER:
|
||||
// No additional checks
|
||||
valid = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new AssertionError("Shouldn't be reached");
|
||||
}
|
||||
|
||||
// Verify number of type annotations matches expected value
|
||||
Matcher matcher = annotationRegex.matcher(annotTypeString);
|
||||
if (expectedAnnotCount > 0) {
|
||||
int i = expectedAnnotCount;
|
||||
int annotCount = 0;
|
||||
while (i > 0) {
|
||||
boolean found = matcher.find();
|
||||
if (found) {
|
||||
i--;
|
||||
annotCount++;
|
||||
} else {
|
||||
errors++;
|
||||
System.err.println("\tExpected annotation not found: " + annotTypeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean found = matcher.find();
|
||||
if (found) {
|
||||
errors++;
|
||||
System.err.println("\tAnnotation found unexpectedly: " + annotTypeString);
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
errors++;
|
||||
System.err.println(typeString + "\n" + annotTypeString +
|
||||
"\n " + valid +
|
||||
"\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final Pattern annotationRegex = Pattern.compile("@TestObjectMethods\\.AnnotType\\((\\p{Digit})+\\)");
|
||||
|
||||
static void testGetAnnotations(Class<?> clazz, boolean annotationsExpectedOnMethods) {
|
||||
System.err.println("Testing getAnnotations on methods of class " + clazz.getName());
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
for (Method m : methods) {
|
||||
Type type = m.getGenericReturnType();
|
||||
AnnotatedType annotType = m.getAnnotatedReturnType();
|
||||
Annotation[] annotations = annotType.getAnnotations();
|
||||
|
||||
boolean isVoid = "void".equals(type.toString());
|
||||
|
||||
if (annotationsExpectedOnMethods && !isVoid) {
|
||||
if (annotations.length == 0 ) {
|
||||
errors++;
|
||||
System.err.println("Expected annotations missing on " + annotType);
|
||||
}
|
||||
} else {
|
||||
if (annotations.length > 0 ) {
|
||||
errors++;
|
||||
System.err.println("Unexpected annotations present on " + annotType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testEqualsReflexivity(Class<?> clazz) {
|
||||
System.err.println("Testing reflexivity of equals on methods of class " + clazz.getName());
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
for (Method m : methods) {
|
||||
checkTypesForEquality(m.getAnnotatedReturnType(),
|
||||
m.getAnnotatedReturnType(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
private static void checkTypesForEquality(AnnotatedType annotType1,
|
||||
AnnotatedType annotType2,
|
||||
boolean expected) {
|
||||
boolean comparison = annotType1.equals(annotType2);
|
||||
|
||||
if (comparison) {
|
||||
int hash1 = annotType1.hashCode();
|
||||
int hash2 = annotType2.hashCode();
|
||||
if (hash1 != hash2) {
|
||||
errors++;
|
||||
System.err.format("Equal AnnotatedTypes with unequal hash codes: %n%s%n%s%n",
|
||||
annotType1.toString(), annotType2.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (comparison != expected) {
|
||||
errors++;
|
||||
System.err.println(annotType1);
|
||||
System.err.println(expected ? " is not equal to " : " is equal to ");
|
||||
System.err.println(annotType2);
|
||||
System.err.println();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For each of the type host classes, the return type of a method
|
||||
* should only equal the return type of that method.
|
||||
*/
|
||||
static void testEquals(Class<?> clazz) {
|
||||
Method[] methods = clazz.getDeclaredMethods();
|
||||
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
else {
|
||||
checkTypesForEquality(methods[i].getAnnotatedReturnType(),
|
||||
methods[j].getAnnotatedReturnType(),
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Roughly, compare the return types of corresponding methods on
|
||||
* TypeHost and AnnotatedtypeHost and verify the AnnotatedType
|
||||
* objects are *not* equal even if their underlying generic types
|
||||
* are.
|
||||
*/
|
||||
static void testAnnotationsMatterForEquals(Class<?> clazz1, Class<?> clazz2) {
|
||||
System.err.println("Testing that presence/absence of annotations matters for equals comparison.");
|
||||
|
||||
String methodName = null;
|
||||
for (Method method : clazz1.getDeclaredMethods()) {
|
||||
if ("void".equals(method.getReturnType().toString())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
methodName = method.getName();
|
||||
try {
|
||||
checkTypesForEquality(method.getAnnotatedReturnType(),
|
||||
clazz2.getDeclaredMethod(methodName).getAnnotatedReturnType(),
|
||||
false);
|
||||
} catch (Exception e) {
|
||||
errors++;
|
||||
System.err.println("Method " + methodName + " not found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void testWildcards() {
|
||||
System.err.println("Testing wildcards");
|
||||
// public @AnnotType(10) Set<? extends Number> fooNumberSet() {return null;}
|
||||
// public @AnnotType(11) Set<@AnnotType(13) ? extends Number> fooNumberSet2() {return null;}
|
||||
AnnotatedWildcardType awt1 = extractWildcard("fooNumberSet");
|
||||
AnnotatedWildcardType awt2 = extractWildcard("fooNumberSet2");
|
||||
|
||||
if (!awt1.equals(extractWildcard("fooNumberSet")) ||
|
||||
!awt2.equals(extractWildcard("fooNumberSet2"))) {
|
||||
errors++;
|
||||
System.err.println("Bad equality comparison on wildcards.");
|
||||
}
|
||||
|
||||
checkTypesForEquality(awt1, awt2, false);
|
||||
|
||||
if (awt2.getAnnotations().length == 0) {
|
||||
errors++;
|
||||
System.err.println("Expected annotations not found.");
|
||||
}
|
||||
}
|
||||
|
||||
private static AnnotatedWildcardType extractWildcard(String methodName) {
|
||||
try {
|
||||
return (AnnotatedWildcardType)
|
||||
(((AnnotatedParameterizedType)(AnnotatedTypeHost.class.getMethod(methodName).
|
||||
getAnnotatedReturnType())).
|
||||
getAnnotatedActualTypeArguments()[0] );
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
static void testFbounds() {
|
||||
// Make sure equals and hashCode work fine for a type
|
||||
// involving an F-bound, in particular Comparable<E> in
|
||||
// java.lang.Enum:
|
||||
//
|
||||
// class Enum<E extends Enum<E>>
|
||||
// implements Constable, Comparable<E>, Serializable
|
||||
|
||||
AnnotatedType[] types = Enum.class.getAnnotatedInterfaces();
|
||||
|
||||
for (int i = 0; i < types.length; i ++) {
|
||||
for (int j = 0; j < types.length; j ++) {
|
||||
checkTypesForEquality(types[i], types[j], i == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The TypeHost and AnnotatedTypeHost classes declare methods with
|
||||
// the same name and signatures but with the AnnotatedTypeHost
|
||||
// methods having annotations on their return type, where
|
||||
// possible.
|
||||
|
||||
static class TypeHost<E, F extends Number> {
|
||||
@AnnotTypeInfo
|
||||
public void fooVoid() {return;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public int foo() {return 0;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public String fooString() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public int[] fooIntArray() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public String[] fooStringArray() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public String [][] fooStringArrayArray() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public Set<String> fooSetString() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public Set<Number> fooSetNumber() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public E fooE() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public F fooF() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public <G> G fooG() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public Set<? extends Number> fooNumberSet() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public Set<? extends Integer> fooNumberSet2() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public Set<? extends Long> fooNumberSet3() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public Set<?> fooObjectSet() {return null;}
|
||||
|
||||
@AnnotTypeInfo
|
||||
public List<? extends Object> fooObjectList() {return null;}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
static @interface AnnotType {
|
||||
int value() default 0;
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
static @interface AnnotTypeInfo {
|
||||
/**
|
||||
* Expected number of @AnnotType
|
||||
*/
|
||||
int count() default 0;
|
||||
|
||||
/**
|
||||
* Relation to genericString output.
|
||||
*/
|
||||
Relation relation() default Relation.EQUAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expected relationship of toString output of AnnotatedType to
|
||||
* toGenericString output of underlying type.
|
||||
*/
|
||||
static private enum Relation {
|
||||
EQUAL,
|
||||
|
||||
/**
|
||||
* The toGenericString output is a postfix of the
|
||||
* AnnotatedType output; a leading annotation is expected.
|
||||
*/
|
||||
POSTFIX,
|
||||
|
||||
/**
|
||||
* If the annotations are stripped from the AnnotatedType
|
||||
* output and whitespace adjusted accordingly, it should equal
|
||||
* the toGenericString output.
|
||||
*/
|
||||
STRIPPED,
|
||||
|
||||
/**
|
||||
* The output of AnnotatedType for arrays would require more
|
||||
* extensive transformation to map to toGenericString output.
|
||||
*/
|
||||
ARRAY,
|
||||
|
||||
/**
|
||||
* Some other, harder to characterize, relationship. Currently
|
||||
* used for a wildcard where Object in "extends Object" is
|
||||
* annotated; the "extends Object" is elided in toGenericString.
|
||||
*/
|
||||
OTHER;
|
||||
}
|
||||
|
||||
static class AnnotatedTypeHost<E, F extends Number> {
|
||||
@AnnotTypeInfo
|
||||
public /*@AnnotType(0)*/ void fooVoid() {return;} // Illegal to annotate void
|
||||
|
||||
@AnnotTypeInfo(count =1, relation = Relation.POSTFIX)
|
||||
@AnnotType(1)
|
||||
public int foo() {return 0;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
|
||||
@AnnotType(2)
|
||||
public String fooString() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.ARRAY)
|
||||
public int @AnnotType(3) [] fooIntArray() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.ARRAY)
|
||||
public String @AnnotType(4) [] fooStringArray() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 3, relation = Relation.ARRAY)
|
||||
@AnnotType(5)
|
||||
public String @AnnotType(0) [] @AnnotType(1) [] fooStringArrayArray() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
|
||||
@AnnotType(6)
|
||||
public Set<String> fooSetString() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
|
||||
@AnnotType(7)
|
||||
public Set<@AnnotType(8) Number> fooSetNumber() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
|
||||
@AnnotType(9)
|
||||
public E fooE() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
|
||||
@AnnotType(10)
|
||||
public F fooF() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
|
||||
@AnnotType(11)
|
||||
public <G> G fooG() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 1, relation = Relation.POSTFIX)
|
||||
@AnnotType(12)
|
||||
public Set<? extends Number> fooNumberSet() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
|
||||
@AnnotType(13)
|
||||
public Set<@AnnotType(14) ? extends Number> fooNumberSet2() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
|
||||
@AnnotType(15)
|
||||
public Set< ? extends @AnnotType(16) Long> fooNumberSet3() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 2, relation = Relation.STRIPPED)
|
||||
@AnnotType(16)
|
||||
public Set<@AnnotType(17) ?> fooObjectSet() {return null;}
|
||||
|
||||
@AnnotTypeInfo(count = 2, relation = Relation.OTHER)
|
||||
@AnnotType(18)
|
||||
public List<? extends @AnnotType(19) Object> fooObjectList() {return null;}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 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 8202471
|
||||
* @summary A nested class's owner can be type annotated if used as a receiver type
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestReceiverTypeOwner<T> {
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
Method method = TestReceiverTypeOwner.Inner.class.getDeclaredMethod("m");
|
||||
AnnotatedType receiverType = method.getAnnotatedReceiverType();
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) receiverType;
|
||||
AnnotatedType owner = parameterizedType.getAnnotatedOwnerType();
|
||||
Annotation[] annotations = owner.getAnnotations();
|
||||
if (annotations.length != 1 || !(annotations[0] instanceof TypeAnnotation)) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
class Inner {
|
||||
void m(@TypeAnnotation TestReceiverTypeOwner<T>.Inner this) { }
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation { }
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 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 8259224
|
||||
* @summary A receiver type's owner type is of the correct type for nested classes.
|
||||
*/
|
||||
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
|
||||
public class TestReceiverTypeOwnerType<T> {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
AnnotatedType nested = Class.forName(TestReceiverTypeOwnerType.class.getTypeName() + "$Nested").getMethod("method").getAnnotatedReceiverType();
|
||||
if (!(nested instanceof AnnotatedParameterizedType)) {
|
||||
throw new AssertionError();
|
||||
} else if (!(nested.getAnnotatedOwnerType() instanceof AnnotatedParameterizedType)) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
AnnotatedType inner = Inner.class.getMethod("method").getAnnotatedReceiverType();
|
||||
if (inner instanceof AnnotatedParameterizedType) {
|
||||
throw new AssertionError();
|
||||
} else if (inner.getAnnotatedOwnerType() instanceof AnnotatedParameterizedType) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
AnnotatedType nestedInner = GenericInner.class.getMethod("method").getAnnotatedReceiverType();
|
||||
if (!(nestedInner instanceof AnnotatedParameterizedType)) {
|
||||
throw new AssertionError();
|
||||
} else if (nestedInner.getAnnotatedOwnerType() instanceof AnnotatedParameterizedType) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
public class Nested {
|
||||
public void method(TestReceiverTypeOwnerType<T>.Nested this) { }
|
||||
}
|
||||
|
||||
public static class Inner {
|
||||
public void method(TestReceiverTypeOwnerType.Inner this) { }
|
||||
}
|
||||
|
||||
public static class GenericInner<S> {
|
||||
public void method(TestReceiverTypeOwnerType.GenericInner<S> this) { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 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 8202471
|
||||
* @summary A constructor's parameterized receiver type's type variables can be type annotated
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
public class TestReceiverTypeParameterizedConstructor<T> {
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
doAssert(TestReceiverTypeParameterizedConstructor.Inner.class);
|
||||
doAssert(TestReceiverTypeParameterizedConstructor.Inner.Inner2.class);
|
||||
}
|
||||
|
||||
private static void doAssert(Class<?> c) throws NoSuchMethodException {
|
||||
Constructor<?> constructor = c.getDeclaredConstructor(c.getDeclaringClass());
|
||||
AnnotatedType receiverType = constructor.getAnnotatedReceiverType();
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) receiverType;
|
||||
int count = 0;
|
||||
do {
|
||||
AnnotatedType[] arguments = parameterizedType.getAnnotatedActualTypeArguments();
|
||||
Annotation[] annotations = arguments[0].getAnnotations();
|
||||
if (annotations.length != 1
|
||||
|| !(annotations[0] instanceof TypeAnnotation)
|
||||
|| ((TypeAnnotation) annotations[0]).value() != count++) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
parameterizedType = (AnnotatedParameterizedType) parameterizedType.getAnnotatedOwnerType();
|
||||
} while (parameterizedType != null);
|
||||
}
|
||||
|
||||
class Inner<S> {
|
||||
Inner(TestReceiverTypeParameterizedConstructor<@TypeAnnotation(0) T> TestReceiverTypeParameterizedConstructor.this) { }
|
||||
|
||||
class Inner2 {
|
||||
Inner2(TestReceiverTypeParameterizedConstructor<@TypeAnnotation(1) T>.Inner<@TypeAnnotation(0) S> TestReceiverTypeParameterizedConstructor.Inner.this) { }
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation {
|
||||
int value();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 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 8202471
|
||||
* @summary A method's parameterized receiver type's type variables can be type annotated
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.*;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class TestReceiverTypeParameterizedMethod<T> {
|
||||
|
||||
public static void main(String[] args) throws NoSuchMethodException {
|
||||
doAssert(TestReceiverTypeParameterizedMethod.class);
|
||||
doAssert(TestReceiverTypeParameterizedMethod.Inner.class);
|
||||
}
|
||||
|
||||
private static void doAssert(Class<?> c) throws NoSuchMethodException {
|
||||
Method method = c.getDeclaredMethod("m");
|
||||
AnnotatedType receiverType = method.getAnnotatedReceiverType();
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) receiverType;
|
||||
int count = 0;
|
||||
do {
|
||||
AnnotatedType[] arguments = parameterizedType.getAnnotatedActualTypeArguments();
|
||||
Annotation[] annotations = arguments[0].getAnnotations();
|
||||
if (annotations.length != 1
|
||||
|| !(annotations[0] instanceof TypeAnnotation)
|
||||
|| ((TypeAnnotation) annotations[0]).value() != count++) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
parameterizedType = (AnnotatedParameterizedType) parameterizedType.getAnnotatedOwnerType();
|
||||
} while (parameterizedType != null);
|
||||
}
|
||||
|
||||
void m(TestReceiverTypeParameterizedMethod<@TypeAnnotation(0) T> this) { }
|
||||
|
||||
class Inner<S> {
|
||||
void m(TestReceiverTypeParameterizedMethod<@TypeAnnotation(1) T>.Inner<@TypeAnnotation(0) S> this) { }
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation {
|
||||
int value();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2020, 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 8202473
|
||||
* @summary Annotations on type variables with multiple bounds should be placed on their respective bound
|
||||
* @compile TypeVariableBoundParameterIndex.java
|
||||
* @run main TypeVariableBoundParameterIndex
|
||||
*/
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.AnnotatedParameterizedType;
|
||||
import java.lang.reflect.AnnotatedType;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/*
|
||||
* A class might have multiple bounds as parameterized types with type annotations on these bounds.
|
||||
* This test assures that these bound annotations are resolved correctly.
|
||||
*/
|
||||
public class TypeVariableBoundParameterIndex {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
TypeVariable<?>[] variables = Sample.class.getTypeParameters();
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
TypeVariable<?> variable = variables[i];
|
||||
AnnotatedType[] bounds = variable.getAnnotatedBounds();
|
||||
AnnotatedType bound = bounds[0];
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) bound;
|
||||
AnnotatedType[] actualTypeArguments = parameterizedType.getAnnotatedActualTypeArguments();
|
||||
Annotation[] annotations = actualTypeArguments[0].getAnnotations();
|
||||
if (annotations.length != 1 || annotations[0].annotationType() != TypeAnnotation.class) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
TypeVariable<?> variable = variables[2];
|
||||
AnnotatedType[] bounds = variable.getAnnotatedBounds();
|
||||
AnnotatedType bound = bounds[0];
|
||||
AnnotatedParameterizedType parameterizedType = (AnnotatedParameterizedType) bound;
|
||||
AnnotatedType[] actualTypeArguments = parameterizedType.getAnnotatedActualTypeArguments();
|
||||
Annotation[] annotations = actualTypeArguments[0].getAnnotations();
|
||||
if (annotations.length != 0) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE_USE)
|
||||
@interface TypeAnnotation { }
|
||||
|
||||
static class Sample<T extends Callable<@TypeAnnotation ?>, S extends Callable<@TypeAnnotation ?>, U extends Callable<?>> { }
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue