Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/RedefineClasses/RedefineAnnotations.java
41153 views
/*1* Copyright (c) 2014, 2021, 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 /test/lib26* @summary Test that type annotations are retained after a retransform27* @requires vm.jvmti28* @modules java.base/jdk.internal.misc29* @modules java.base/jdk.internal.org.objectweb.asm30* java.instrument31* jdk.jartool/sun.tools.jar32* @run main RedefineAnnotations buildagent33* @run main/othervm -javaagent:redefineagent.jar RedefineAnnotations34*/3536import static jdk.test.lib.Asserts.assertTrue;37import jdk.test.lib.helpers.ClassFileInstaller;38import java.io.FileNotFoundException;39import java.io.PrintWriter;40import java.lang.NoSuchFieldException;41import java.lang.NoSuchMethodException;42import java.lang.RuntimeException;43import java.lang.annotation.Annotation;44import java.lang.annotation.ElementType;45import java.lang.annotation.Retention;46import java.lang.annotation.RetentionPolicy;47import java.lang.annotation.Target;48import java.lang.instrument.ClassFileTransformer;49import java.lang.instrument.IllegalClassFormatException;50import java.lang.instrument.Instrumentation;51import java.lang.instrument.UnmodifiableClassException;52import java.lang.reflect.AnnotatedArrayType;53import java.lang.reflect.AnnotatedParameterizedType;54import java.lang.reflect.AnnotatedType;55import java.lang.reflect.AnnotatedWildcardType;56import java.lang.reflect.Executable;57import java.lang.reflect.TypeVariable;58import java.security.ProtectionDomain;59import java.util.Arrays;60import java.util.LinkedList;61import java.util.List;62import java.util.Map;63import jdk.internal.org.objectweb.asm.ClassReader;64import jdk.internal.org.objectweb.asm.ClassVisitor;65import jdk.internal.org.objectweb.asm.ClassWriter;66import jdk.internal.org.objectweb.asm.FieldVisitor;67import static jdk.internal.org.objectweb.asm.Opcodes.ASM7;6869@Retention(RetentionPolicy.RUNTIME)70@Target(ElementType.TYPE_USE)71@interface TestAnn {72String site();73}7475public class RedefineAnnotations {76static Instrumentation inst;77public static void premain(String agentArgs, Instrumentation inst) {78RedefineAnnotations.inst = inst;79}8081static class Transformer implements ClassFileTransformer {8283public byte[] asm(ClassLoader loader, String className,84Class<?> classBeingRedefined,85ProtectionDomain protectionDomain, byte[] classfileBuffer)86throws IllegalClassFormatException {8788ClassWriter cw = new ClassWriter(0);89ClassVisitor cv = new ReAddDummyFieldsClassVisitor(ASM7, cw) { };90ClassReader cr = new ClassReader(classfileBuffer);91cr.accept(cv, 0);92return cw.toByteArray();93}9495public class ReAddDummyFieldsClassVisitor extends ClassVisitor {9697LinkedList<F> fields = new LinkedList<>();9899public ReAddDummyFieldsClassVisitor(int api, ClassVisitor cv) {100super(api, cv);101}102103@Override public FieldVisitor visitField(int access, String name,104String desc, String signature, Object value) {105if (name.startsWith("dummy")) {106// Remove dummy field107fields.addLast(new F(access, name, desc, signature, value));108return null;109}110return cv.visitField(access, name, desc, signature, value);111}112113@Override public void visitEnd() {114F f;115while ((f = fields.pollFirst()) != null) {116// Re-add dummy fields117cv.visitField(f.access, f.name, f.desc, f.signature, f.value);118}119}120121private class F {122private int access;123private String name;124private String desc;125private String signature;126private Object value;127F(int access, String name, String desc, String signature, Object value) {128this.access = access;129this.name = name;130this.desc = desc;131this.signature = signature;132this.value = value;133}134}135}136137@Override public byte[] transform(ClassLoader loader, String className,138Class<?> classBeingRedefined,139ProtectionDomain protectionDomain, byte[] classfileBuffer)140throws IllegalClassFormatException {141142if (className.contains("TypeAnnotatedTestClass")) {143try {144// Here we remove and re-add the dummy fields. This shuffles the constant pool145return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);146} catch (Throwable e) {147// The retransform native code that called this method does not propagate148// exceptions. Instead of getting an uninformative generic error, catch149// problems here and print it, then exit.150e.printStackTrace();151System.exit(1);152}153}154return null;155}156}157158private static void buildAgent() {159try {160ClassFileInstaller.main("RedefineAnnotations");161} catch (Exception e) {162throw new RuntimeException("Could not write agent classfile", e);163}164165try {166PrintWriter pw = new PrintWriter("MANIFEST.MF");167pw.println("Premain-Class: RedefineAnnotations");168pw.println("Agent-Class: RedefineAnnotations");169pw.println("Can-Retransform-Classes: true");170pw.close();171} catch (FileNotFoundException e) {172throw new RuntimeException("Could not write manifest file for the agent", e);173}174175sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");176if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineAnnotations.class" })) {177throw new RuntimeException("Could not write the agent jar file");178}179}180181public static void main(String argv[]) throws NoSuchFieldException, NoSuchMethodException {182if (argv.length == 1 && argv[0].equals("buildagent")) {183buildAgent();184return;185}186187if (inst == null) {188throw new RuntimeException("Instrumentation object was null");189}190191RedefineAnnotations test = new RedefineAnnotations();192test.testTransformAndVerify();193}194195// Class type annotations196private Annotation classTypeParameterTA;197private Annotation extendsTA;198private Annotation implementsTA;199200// Field type annotations201private Annotation fieldTA;202private Annotation innerTA;203private Annotation[] arrayTA = new Annotation[4];204private Annotation[] mapTA = new Annotation[5];205206// Method type annotations207private Annotation returnTA, methodTypeParameterTA, formalParameterTA, throwsTA;208209private void testTransformAndVerify()210throws NoSuchFieldException, NoSuchMethodException {211212Class<TypeAnnotatedTestClass> c = TypeAnnotatedTestClass.class;213Class<?> myClass = c;214215/*216* Verify that the expected annotations are where they should be before transform.217*/218verifyClassTypeAnnotations(c);219verifyFieldTypeAnnotations(c);220verifyMethodTypeAnnotations(c);221222try {223inst.addTransformer(new Transformer(), true);224inst.retransformClasses(myClass);225} catch (UnmodifiableClassException e) {226throw new RuntimeException(e);227}228229/*230* Verify that the expected annotations are where they should be after transform.231* Also verify that before and after are equal.232*/233verifyClassTypeAnnotations(c);234verifyFieldTypeAnnotations(c);235verifyMethodTypeAnnotations(c);236}237238private void verifyClassTypeAnnotations(Class c) {239Annotation anno;240241anno = c.getTypeParameters()[0].getAnnotations()[0];242verifyTestAnn(classTypeParameterTA, anno, "classTypeParameter");243classTypeParameterTA = anno;244245anno = c.getAnnotatedSuperclass().getAnnotations()[0];246verifyTestAnn(extendsTA, anno, "extends");247extendsTA = anno;248249anno = c.getAnnotatedInterfaces()[0].getAnnotations()[0];250verifyTestAnn(implementsTA, anno, "implements");251implementsTA = anno;252}253254private void verifyFieldTypeAnnotations(Class c)255throws NoSuchFieldException, NoSuchMethodException {256257verifyBasicFieldTypeAnnotations(c);258verifyInnerFieldTypeAnnotations(c);259verifyArrayFieldTypeAnnotations(c);260verifyMapFieldTypeAnnotations(c);261}262263private void verifyBasicFieldTypeAnnotations(Class c)264throws NoSuchFieldException, NoSuchMethodException {265266Annotation anno = c.getDeclaredField("typeAnnotatedBoolean").getAnnotatedType().getAnnotations()[0];267verifyTestAnn(fieldTA, anno, "field");268fieldTA = anno;269}270271private void verifyInnerFieldTypeAnnotations(Class c)272throws NoSuchFieldException, NoSuchMethodException {273274AnnotatedType at = c.getDeclaredField("typeAnnotatedInner").getAnnotatedType();275Annotation anno = at.getAnnotations()[0];276verifyTestAnn(innerTA, anno, "inner");277innerTA = anno;278}279280private void verifyArrayFieldTypeAnnotations(Class c)281throws NoSuchFieldException, NoSuchMethodException {282283Annotation anno;284AnnotatedType at;285286at = c.getDeclaredField("typeAnnotatedArray").getAnnotatedType();287anno = at.getAnnotations()[0];288verifyTestAnn(arrayTA[0], anno, "array1");289arrayTA[0] = anno;290291for (int i = 1; i <= 3; i++) {292at = ((AnnotatedArrayType) at).getAnnotatedGenericComponentType();293anno = at.getAnnotations()[0];294verifyTestAnn(arrayTA[i], anno, "array" + (i + 1));295arrayTA[i] = anno;296}297}298299private void verifyMapFieldTypeAnnotations(Class c)300throws NoSuchFieldException, NoSuchMethodException {301302Annotation anno;303AnnotatedType atBase;304AnnotatedType atParameter;305atBase = c.getDeclaredField("typeAnnotatedMap").getAnnotatedType();306307anno = atBase.getAnnotations()[0];308verifyTestAnn(mapTA[0], anno, "map1");309mapTA[0] = anno;310311atParameter =312((AnnotatedParameterizedType) atBase).313getAnnotatedActualTypeArguments()[0];314anno = ((AnnotatedWildcardType) atParameter).getAnnotations()[0];315verifyTestAnn(mapTA[1], anno, "map2");316mapTA[1] = anno;317318anno =319((AnnotatedWildcardType) atParameter).320getAnnotatedUpperBounds()[0].getAnnotations()[0];321verifyTestAnn(mapTA[2], anno, "map3");322mapTA[2] = anno;323324atParameter =325((AnnotatedParameterizedType) atBase).326getAnnotatedActualTypeArguments()[1];327anno = ((AnnotatedParameterizedType) atParameter).getAnnotations()[0];328verifyTestAnn(mapTA[3], anno, "map4");329mapTA[3] = anno;330331anno =332((AnnotatedParameterizedType) atParameter).333getAnnotatedActualTypeArguments()[0].getAnnotations()[0];334verifyTestAnn(mapTA[4], anno, "map5");335mapTA[4] = anno;336}337338private void verifyMethodTypeAnnotations(Class c)339throws NoSuchFieldException, NoSuchMethodException {340Annotation anno;341Executable typeAnnotatedMethod =342c.getDeclaredMethod("typeAnnotatedMethod", TypeAnnotatedTestClass.class);343344anno = typeAnnotatedMethod.getAnnotatedReturnType().getAnnotations()[0];345verifyTestAnn(returnTA, anno, "return");346returnTA = anno;347348anno = typeAnnotatedMethod.getTypeParameters()[0].getAnnotations()[0];349verifyTestAnn(methodTypeParameterTA, anno, "methodTypeParameter");350methodTypeParameterTA = anno;351352anno = typeAnnotatedMethod.getAnnotatedParameterTypes()[0].getAnnotations()[0];353verifyTestAnn(formalParameterTA, anno, "formalParameter");354formalParameterTA = anno;355356anno = typeAnnotatedMethod.getAnnotatedExceptionTypes()[0].getAnnotations()[0];357verifyTestAnn(throwsTA, anno, "throws");358throwsTA = anno;359}360361private static void verifyTestAnn(Annotation verifyAgainst, Annotation anno, String expectedSite) {362verifyTestAnnSite(anno, expectedSite);363364// When called before transform verifyAgainst will be null, when called365// after transform it will be the annotation from before the transform366if (verifyAgainst != null) {367assertTrue(anno.equals(verifyAgainst),368"Annotations do not match before and after." +369" Before: \"" + verifyAgainst + "\", After: \"" + anno + "\"");370}371}372373private static void verifyTestAnnSite(Annotation testAnn, String expectedSite) {374String expectedAnn = "@TestAnn(site=\"" + expectedSite + "\")";375assertTrue(testAnn.toString().equals(expectedAnn),376"Expected \"" + expectedAnn + "\", got \"" + testAnn + "\"");377}378379public static class TypeAnnotatedTestClass <@TestAnn(site="classTypeParameter") S,T>380extends @TestAnn(site="extends") Thread381implements @TestAnn(site="implements") Runnable {382383public @TestAnn(site="field") boolean typeAnnotatedBoolean;384385public386RedefineAnnotations.387@TestAnn(site="inner") TypeAnnotatedTestClass388typeAnnotatedInner;389390public391@TestAnn(site="array4") boolean392@TestAnn(site="array1") []393@TestAnn(site="array2") []394@TestAnn(site="array3") []395typeAnnotatedArray;396397public @TestAnn(site="map1") Map398<@TestAnn(site="map2") ? extends @TestAnn(site="map3") String,399@TestAnn(site="map4") List<@TestAnn(site="map5") Object>> typeAnnotatedMap;400401public int dummy1;402public int dummy2;403public int dummy3;404405@TestAnn(site="return") <@TestAnn(site="methodTypeParameter") U,V> Class406typeAnnotatedMethod(@TestAnn(site="formalParameter") TypeAnnotatedTestClass arg)407throws @TestAnn(site="throws") ClassNotFoundException {408409@TestAnn(site="local_variable_type") int foo = 0;410throw new ClassNotFoundException();411}412413public void run() {}414}415}416417418