Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/runtime/RedefineTests/RedefineAnnotations.java
32284 views
/*1* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @library /testlibrary26* @summary Test that type annotations are retained after a retransform27* @run main RedefineAnnotations buildagent28* @run main/othervm -javaagent:redefineagent.jar RedefineAnnotations29*/3031import static com.oracle.java.testlibrary.Asserts.assertTrue;32import java.io.FileNotFoundException;33import java.io.PrintWriter;34import java.lang.NoSuchFieldException;35import java.lang.NoSuchMethodException;36import java.lang.RuntimeException;37import java.lang.annotation.Annotation;38import java.lang.annotation.ElementType;39import java.lang.annotation.Retention;40import java.lang.annotation.RetentionPolicy;41import java.lang.annotation.Target;42import java.lang.instrument.ClassFileTransformer;43import java.lang.instrument.IllegalClassFormatException;44import java.lang.instrument.Instrumentation;45import java.lang.instrument.UnmodifiableClassException;46import java.lang.reflect.AnnotatedArrayType;47import java.lang.reflect.AnnotatedParameterizedType;48import java.lang.reflect.AnnotatedType;49import java.lang.reflect.AnnotatedWildcardType;50import java.lang.reflect.Executable;51import java.lang.reflect.TypeVariable;52import java.security.ProtectionDomain;53import java.util.Arrays;54import java.util.LinkedList;55import java.util.List;56import java.util.Map;57import jdk.internal.org.objectweb.asm.ClassReader;58import jdk.internal.org.objectweb.asm.ClassVisitor;59import jdk.internal.org.objectweb.asm.ClassWriter;60import jdk.internal.org.objectweb.asm.FieldVisitor;61import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;6263@Retention(RetentionPolicy.RUNTIME)64@Target(ElementType.TYPE_USE)65@interface TestAnn {66String site();67}6869public class RedefineAnnotations {70static Instrumentation inst;71public static void premain(String agentArgs, Instrumentation inst) {72RedefineAnnotations.inst = inst;73}7475static class Transformer implements ClassFileTransformer {7677public byte[] asm(ClassLoader loader, String className,78Class<?> classBeingRedefined,79ProtectionDomain protectionDomain, byte[] classfileBuffer)80throws IllegalClassFormatException {8182ClassWriter cw = new ClassWriter(0);83ClassVisitor cv = new ReAddDummyFieldsClassVisitor(ASM5, cw) { };84ClassReader cr = new ClassReader(classfileBuffer);85cr.accept(cv, 0);86return cw.toByteArray();87}8889public class ReAddDummyFieldsClassVisitor extends ClassVisitor {9091LinkedList<F> fields = new LinkedList<>();9293public ReAddDummyFieldsClassVisitor(int api, ClassVisitor cv) {94super(api, cv);95}9697@Override public FieldVisitor visitField(int access, String name,98String desc, String signature, Object value) {99if (name.startsWith("dummy")) {100// Remove dummy field101fields.addLast(new F(access, name, desc, signature, value));102return null;103}104return cv.visitField(access, name, desc, signature, value);105}106107@Override public void visitEnd() {108F f;109while ((f = fields.pollFirst()) != null) {110// Re-add dummy fields111cv.visitField(f.access, f.name, f.desc, f.signature, f.value);112}113}114115private class F {116private int access;117private String name;118private String desc;119private String signature;120private Object value;121F(int access, String name, String desc, String signature, Object value) {122this.access = access;123this.name = name;124this.desc = desc;125this.signature = signature;126this.value = value;127}128}129}130131@Override public byte[] transform(ClassLoader loader, String className,132Class<?> classBeingRedefined,133ProtectionDomain protectionDomain, byte[] classfileBuffer)134throws IllegalClassFormatException {135136if (className.contains("TypeAnnotatedTestClass")) {137try {138// Here we remove and re-add the dummy fields. This shuffles the constant pool139return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);140} catch (Throwable e) {141// The retransform native code that called this method does not propagate142// exceptions. Instead of getting an uninformative generic error, catch143// problems here and print it, then exit.144e.printStackTrace();145System.exit(1);146}147}148return null;149}150}151152private static void buildAgent() {153try {154ClassFileInstaller.main("RedefineAnnotations");155} catch (Exception e) {156throw new RuntimeException("Could not write agent classfile", e);157}158159try {160PrintWriter pw = new PrintWriter("MANIFEST.MF");161pw.println("Premain-Class: RedefineAnnotations");162pw.println("Agent-Class: RedefineAnnotations");163pw.println("Can-Retransform-Classes: true");164pw.close();165} catch (FileNotFoundException e) {166throw new RuntimeException("Could not write manifest file for the agent", e);167}168169sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");170if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineAnnotations.class" })) {171throw new RuntimeException("Could not write the agent jar file");172}173}174175public static void main(String argv[]) throws NoSuchFieldException, NoSuchMethodException {176if (argv.length == 1 && argv[0].equals("buildagent")) {177buildAgent();178return;179}180181if (inst == null) {182throw new RuntimeException("Instrumentation object was null");183}184185RedefineAnnotations test = new RedefineAnnotations();186test.testTransformAndVerify();187}188189// Class type annotations190private Annotation classTypeParameterTA;191private Annotation extendsTA;192private Annotation implementsTA;193194// Field type annotations195private Annotation fieldTA;196private Annotation innerTA;197private Annotation[] arrayTA = new Annotation[4];198private Annotation[] mapTA = new Annotation[5];199200// Method type annotations201private Annotation returnTA, methodTypeParameterTA, formalParameterTA, throwsTA;202203private void testTransformAndVerify()204throws NoSuchFieldException, NoSuchMethodException {205206Class<TypeAnnotatedTestClass> c = TypeAnnotatedTestClass.class;207Class<?> myClass = c;208209/*210* Verify that the expected annotations are where they should be before transform.211*/212verifyClassTypeAnnotations(c);213verifyFieldTypeAnnotations(c);214verifyMethodTypeAnnotations(c);215216try {217inst.addTransformer(new Transformer(), true);218inst.retransformClasses(myClass);219} catch (UnmodifiableClassException e) {220throw new RuntimeException(e);221}222223/*224* Verify that the expected annotations are where they should be after transform.225* Also verify that before and after are equal.226*/227verifyClassTypeAnnotations(c);228verifyFieldTypeAnnotations(c);229verifyMethodTypeAnnotations(c);230}231232private void verifyClassTypeAnnotations(Class c) {233Annotation anno;234235anno = c.getTypeParameters()[0].getAnnotations()[0];236verifyTestAnn(classTypeParameterTA, anno, "classTypeParameter");237classTypeParameterTA = anno;238239anno = c.getAnnotatedSuperclass().getAnnotations()[0];240verifyTestAnn(extendsTA, anno, "extends");241extendsTA = anno;242243anno = c.getAnnotatedInterfaces()[0].getAnnotations()[0];244verifyTestAnn(implementsTA, anno, "implements");245implementsTA = anno;246}247248private void verifyFieldTypeAnnotations(Class c)249throws NoSuchFieldException, NoSuchMethodException {250251verifyBasicFieldTypeAnnotations(c);252verifyInnerFieldTypeAnnotations(c);253verifyArrayFieldTypeAnnotations(c);254verifyMapFieldTypeAnnotations(c);255}256257private void verifyBasicFieldTypeAnnotations(Class c)258throws NoSuchFieldException, NoSuchMethodException {259260Annotation anno = c.getDeclaredField("typeAnnotatedBoolean").getAnnotatedType().getAnnotations()[0];261verifyTestAnn(fieldTA, anno, "field");262fieldTA = anno;263}264265private void verifyInnerFieldTypeAnnotations(Class c)266throws NoSuchFieldException, NoSuchMethodException {267268AnnotatedType at = c.getDeclaredField("typeAnnotatedInner").getAnnotatedType();269Annotation anno = at.getAnnotations()[0];270verifyTestAnn(innerTA, anno, "inner");271innerTA = anno;272}273274private void verifyArrayFieldTypeAnnotations(Class c)275throws NoSuchFieldException, NoSuchMethodException {276277Annotation anno;278AnnotatedType at;279280at = c.getDeclaredField("typeAnnotatedArray").getAnnotatedType();281anno = at.getAnnotations()[0];282verifyTestAnn(arrayTA[0], anno, "array1");283arrayTA[0] = anno;284285for (int i = 1; i <= 3; i++) {286at = ((AnnotatedArrayType) at).getAnnotatedGenericComponentType();287anno = at.getAnnotations()[0];288verifyTestAnn(arrayTA[i], anno, "array" + (i + 1));289arrayTA[i] = anno;290}291}292293private void verifyMapFieldTypeAnnotations(Class c)294throws NoSuchFieldException, NoSuchMethodException {295296Annotation anno;297AnnotatedType atBase;298AnnotatedType atParameter;299atBase = c.getDeclaredField("typeAnnotatedMap").getAnnotatedType();300301anno = atBase.getAnnotations()[0];302verifyTestAnn(mapTA[0], anno, "map1");303mapTA[0] = anno;304305atParameter =306((AnnotatedParameterizedType) atBase).307getAnnotatedActualTypeArguments()[0];308anno = ((AnnotatedWildcardType) atParameter).getAnnotations()[0];309verifyTestAnn(mapTA[1], anno, "map2");310mapTA[1] = anno;311312anno =313((AnnotatedWildcardType) atParameter).314getAnnotatedUpperBounds()[0].getAnnotations()[0];315verifyTestAnn(mapTA[2], anno, "map3");316mapTA[2] = anno;317318atParameter =319((AnnotatedParameterizedType) atBase).320getAnnotatedActualTypeArguments()[1];321anno = ((AnnotatedParameterizedType) atParameter).getAnnotations()[0];322verifyTestAnn(mapTA[3], anno, "map4");323mapTA[3] = anno;324325anno =326((AnnotatedParameterizedType) atParameter).327getAnnotatedActualTypeArguments()[0].getAnnotations()[0];328verifyTestAnn(mapTA[4], anno, "map5");329mapTA[4] = anno;330}331332private void verifyMethodTypeAnnotations(Class c)333throws NoSuchFieldException, NoSuchMethodException {334Annotation anno;335Executable typeAnnotatedMethod =336c.getDeclaredMethod("typeAnnotatedMethod", TypeAnnotatedTestClass.class);337338anno = typeAnnotatedMethod.getAnnotatedReturnType().getAnnotations()[0];339verifyTestAnn(returnTA, anno, "return");340returnTA = anno;341342anno = typeAnnotatedMethod.getTypeParameters()[0].getAnnotations()[0];343verifyTestAnn(methodTypeParameterTA, anno, "methodTypeParameter");344methodTypeParameterTA = anno;345346anno = typeAnnotatedMethod.getAnnotatedParameterTypes()[0].getAnnotations()[0];347verifyTestAnn(formalParameterTA, anno, "formalParameter");348formalParameterTA = anno;349350anno = typeAnnotatedMethod.getAnnotatedExceptionTypes()[0].getAnnotations()[0];351verifyTestAnn(throwsTA, anno, "throws");352throwsTA = anno;353}354355private static void verifyTestAnn(Annotation verifyAgainst, Annotation anno, String expectedSite) {356verifyTestAnnSite(anno, expectedSite);357358// When called before transform verifyAgainst will be null, when called359// after transform it will be the annotation from before the transform360if (verifyAgainst != null) {361assertTrue(anno.equals(verifyAgainst),362"Annotations do not match before and after." +363" Before: \"" + verifyAgainst + "\", After: \"" + anno + "\"");364}365}366367private static void verifyTestAnnSite(Annotation testAnn, String expectedSite) {368String expectedAnn = "@TestAnn(site=" + expectedSite + ")";369assertTrue(testAnn.toString().equals(expectedAnn),370"Expected \"" + expectedAnn + "\", got \"" + testAnn + "\"");371}372373public static class TypeAnnotatedTestClass <@TestAnn(site="classTypeParameter") S,T>374extends @TestAnn(site="extends") Thread375implements @TestAnn(site="implements") Runnable {376377public @TestAnn(site="field") boolean typeAnnotatedBoolean;378379public380RedefineAnnotations.381@TestAnn(site="inner") TypeAnnotatedTestClass382typeAnnotatedInner;383384public385@TestAnn(site="array4") boolean386@TestAnn(site="array1") []387@TestAnn(site="array2") []388@TestAnn(site="array3") []389typeAnnotatedArray;390391public @TestAnn(site="map1") Map392<@TestAnn(site="map2") ? extends @TestAnn(site="map3") String,393@TestAnn(site="map4") List<@TestAnn(site="map5") Object>> typeAnnotatedMap;394395public int dummy1;396public int dummy2;397public int dummy3;398399@TestAnn(site="return") <@TestAnn(site="methodTypeParameter") U,V> Class400typeAnnotatedMethod(@TestAnn(site="formalParameter") TypeAnnotatedTestClass arg)401throws @TestAnn(site="throws") ClassNotFoundException {402403@TestAnn(site="local_variable_type") int foo = 0;404throw new ClassNotFoundException();405}406407public void run() {}408}409}410411412