8173056: Add test that captures current behavior of annotations with invalid annotation types
Reviewed-by: redestad
This commit is contained in:
parent
46c1da44bd
commit
f2998da973
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 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
|
||||
@ -27,9 +27,15 @@
|
||||
* Create class file using ASM, slightly modified the ASMifier output
|
||||
*/
|
||||
|
||||
import sun.reflect.annotation.AnnotationType;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.AnnotationFormatError;
|
||||
import org.testng.annotations.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/*
|
||||
* @test
|
||||
@ -37,27 +43,380 @@ import org.testng.annotations.*;
|
||||
* @summary Verify valid annotation
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* @modules java.base/sun.reflect.annotation
|
||||
* @clean AnnotationWithVoidReturn.class AnnotationWithParameter.class
|
||||
* @compile -XDignore.symbol.file ClassFileGenerator.java
|
||||
* @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 {
|
||||
|
||||
@AnnotationWithParameter
|
||||
@AnnotationWithVoidReturn
|
||||
static class BadAnnotation {
|
||||
//=======================================================
|
||||
// GoodAnnotation...
|
||||
|
||||
@GoodAnnotation
|
||||
static class HolderA {
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExpectedExceptions(IllegalArgumentException.class)
|
||||
public void annotationValidationIAE() {
|
||||
AnnotationType.getInstance(AnnotationWithParameter.class);
|
||||
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 annotationValidationAFE() {
|
||||
BadAnnotation.class.getAnnotation(AnnotationWithVoidReturn.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 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
|
||||
@ -40,6 +40,13 @@ public class ClassFileGenerator {
|
||||
public static void main(String... args) throws Exception {
|
||||
classFileWriter("AnnotationWithVoidReturn.class", AnnoationWithVoidReturnDump.dump());
|
||||
classFileWriter("AnnotationWithParameter.class", AnnoationWithParameterDump.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 {
|
||||
@ -49,14 +56,13 @@ public class ClassFileGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Following code create equivalent classfile,
|
||||
which is not allowed by javac.
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithVoidReturn {
|
||||
void m() default 1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnoationWithVoidReturnDump implements Opcodes {
|
||||
@ -65,7 +71,7 @@ public class ClassFileGenerator {
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + +ACC_INTERFACE,
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"AnnotationWithVoidReturn", null,
|
||||
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
|
||||
|
||||
@ -91,14 +97,13 @@ public class ClassFileGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Following code create equivalent classfile,
|
||||
which is not allowed by javac.
|
||||
/* Following code creates equivalent classfile, which is not allowed by javac:
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface AnnotationWithParameter {
|
||||
int m(int x);
|
||||
int m(int x) default -1;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
private static class AnnoationWithParameterDump implements Opcodes {
|
||||
@ -136,4 +141,250 @@ public class ClassFileGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 implements Opcodes {
|
||||
public static byte[] dump() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"AnnotationWithExtraInterface", null,
|
||||
"java/lang/Object", new String[]{"java/lang/annotation/Annotation",
|
||||
"java/io/Serializable"});
|
||||
|
||||
{
|
||||
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
|
||||
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
|
||||
"RUNTIME");
|
||||
av0.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
av0 = mv.visitAnnotationDefault();
|
||||
av0.visit(null, new Integer(1));
|
||||
av0.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 implements Opcodes {
|
||||
public static byte[] dump() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"AnnotationWithException", null,
|
||||
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
|
||||
|
||||
{
|
||||
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
|
||||
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
|
||||
"RUNTIME");
|
||||
av0.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null,
|
||||
new String[] {"java/lang/Exception"});
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
av0 = mv.visitAnnotationDefault();
|
||||
av0.visit(null, new Integer(1));
|
||||
av0.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 implements Opcodes {
|
||||
public static byte[] dump() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"AnnotationWithHashCode", null,
|
||||
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
|
||||
|
||||
{
|
||||
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
|
||||
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
|
||||
"RUNTIME");
|
||||
av0.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "hashCode", "()I", null, null);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
av0 = mv.visitAnnotationDefault();
|
||||
av0.visit(null, new Integer(1));
|
||||
av0.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 implements Opcodes {
|
||||
public static byte[] dump() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
MethodVisitor mv, dv;
|
||||
AnnotationVisitor av0;
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ANNOTATION + ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"AnnotationWithDefaultMember", null,
|
||||
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
|
||||
|
||||
{
|
||||
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
|
||||
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
|
||||
"RUNTIME");
|
||||
av0.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
av0 = mv.visitAnnotationDefault();
|
||||
av0.visit(null, new Integer(1));
|
||||
av0.visitEnd();
|
||||
}
|
||||
{
|
||||
dv = cw.visitMethod(ACC_PUBLIC, "d", "()I", null, null);
|
||||
dv.visitMaxs(1, 1);
|
||||
dv.visitCode();
|
||||
dv.visitInsn(Opcodes.ICONST_2);
|
||||
dv.visitInsn(Opcodes.IRETURN);
|
||||
dv.visitEnd();
|
||||
}
|
||||
{
|
||||
av0 = dv.visitAnnotationDefault();
|
||||
av0.visit(null, new Integer(2));
|
||||
av0.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 implements Opcodes {
|
||||
public static byte[] dump() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
MethodVisitor mv;
|
||||
AnnotationVisitor av0;
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + /* ACC_ANNOTATION +*/ ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"AnnotationWithoutAnnotationAccessModifier", null,
|
||||
"java/lang/Object", new String[]{"java/lang/annotation/Annotation"});
|
||||
|
||||
{
|
||||
av0 = cw.visitAnnotation("Ljava/lang/annotation/Retention;", true);
|
||||
av0.visitEnum("value", "Ljava/lang/annotation/RetentionPolicy;",
|
||||
"RUNTIME");
|
||||
av0.visitEnd();
|
||||
}
|
||||
{
|
||||
mv = cw.visitMethod(ACC_PUBLIC + ACC_ABSTRACT, "m", "()I", null, null);
|
||||
mv.visitEnd();
|
||||
}
|
||||
{
|
||||
av0 = mv.visitAnnotationDefault();
|
||||
av0.visit(null, new Integer(1));
|
||||
av0.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 implements Opcodes {
|
||||
public static byte[] dump() throws Exception {
|
||||
ClassWriter cw = new ClassWriter(0);
|
||||
|
||||
cw.visit(52, ACC_PUBLIC + ACC_ABSTRACT + ACC_INTERFACE,
|
||||
"HolderX", null,
|
||||
"java/lang/Object", new String[0]);
|
||||
|
||||
{
|
||||
AnnotationVisitor av0;
|
||||
av0 = cw.visitAnnotation("LGoodAnnotation;", true);
|
||||
av0.visitEnd();
|
||||
av0 = cw.visitAnnotation("LAnnotationWithoutAnnotationAccessModifier;", true);
|
||||
av0.visitEnd();
|
||||
}
|
||||
cw.visitEnd();
|
||||
|
||||
return cw.toByteArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
33
jdk/test/java/lang/annotation/GoodAnnotation.java
Normal file
33
jdk/test/java/lang/annotation/GoodAnnotation.java
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 {}
|
Loading…
x
Reference in New Issue
Block a user