test/runtime/RedefineTests/RedefineAnnotations.java

Mon, 06 Nov 2017 16:51:47 +0800

author
aoqi
date
Mon, 06 Nov 2017 16:51:47 +0800
changeset 7997
6cbff0651f1a
parent 7327
50054b63f0aa
permissions
-rw-r--r--

[Code Reorganization] remove trailing whitespace to pass jcheck test

     1 /*
     2  * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  */
    24 /*
    25  * @test
    26  * @library /testlibrary
    27  * @summary Test that type annotations are retained after a retransform
    28  * @run main RedefineAnnotations buildagent
    29  * @run main/othervm -javaagent:redefineagent.jar RedefineAnnotations
    30  */
    32 import static com.oracle.java.testlibrary.Asserts.assertTrue;
    33 import java.io.FileNotFoundException;
    34 import java.io.PrintWriter;
    35 import java.lang.NoSuchFieldException;
    36 import java.lang.NoSuchMethodException;
    37 import java.lang.RuntimeException;
    38 import java.lang.annotation.Annotation;
    39 import java.lang.annotation.ElementType;
    40 import java.lang.annotation.Retention;
    41 import java.lang.annotation.RetentionPolicy;
    42 import java.lang.annotation.Target;
    43 import java.lang.instrument.ClassFileTransformer;
    44 import java.lang.instrument.IllegalClassFormatException;
    45 import java.lang.instrument.Instrumentation;
    46 import java.lang.instrument.UnmodifiableClassException;
    47 import java.lang.reflect.AnnotatedArrayType;
    48 import java.lang.reflect.AnnotatedParameterizedType;
    49 import java.lang.reflect.AnnotatedType;
    50 import java.lang.reflect.AnnotatedWildcardType;
    51 import java.lang.reflect.Executable;
    52 import java.lang.reflect.TypeVariable;
    53 import java.security.ProtectionDomain;
    54 import java.util.Arrays;
    55 import java.util.LinkedList;
    56 import java.util.List;
    57 import java.util.Map;
    58 import jdk.internal.org.objectweb.asm.ClassReader;
    59 import jdk.internal.org.objectweb.asm.ClassVisitor;
    60 import jdk.internal.org.objectweb.asm.ClassWriter;
    61 import jdk.internal.org.objectweb.asm.FieldVisitor;
    62 import static jdk.internal.org.objectweb.asm.Opcodes.ASM5;
    64 @Retention(RetentionPolicy.RUNTIME)
    65 @Target(ElementType.TYPE_USE)
    66 @interface TestAnn {
    67     String site();
    68 }
    70 public class RedefineAnnotations {
    71     static Instrumentation inst;
    72     public static void premain(String agentArgs, Instrumentation inst) {
    73         RedefineAnnotations.inst = inst;
    74     }
    76     static class Transformer implements ClassFileTransformer {
    78         public byte[] asm(ClassLoader loader, String className,
    79                 Class<?> classBeingRedefined,
    80                 ProtectionDomain protectionDomain, byte[] classfileBuffer)
    81             throws IllegalClassFormatException {
    83             ClassWriter cw = new ClassWriter(0);
    84             ClassVisitor cv = new ReAddDummyFieldsClassVisitor(ASM5, cw) { };
    85             ClassReader cr = new ClassReader(classfileBuffer);
    86             cr.accept(cv, 0);
    87             return cw.toByteArray();
    88         }
    90         public class ReAddDummyFieldsClassVisitor extends ClassVisitor {
    92             LinkedList<F> fields = new LinkedList<>();
    94             public ReAddDummyFieldsClassVisitor(int api, ClassVisitor cv) {
    95                 super(api, cv);
    96             }
    98             @Override public FieldVisitor visitField(int access, String name,
    99                     String desc, String signature, Object value) {
   100                 if (name.startsWith("dummy")) {
   101                     // Remove dummy field
   102                     fields.addLast(new F(access, name, desc, signature, value));
   103                     return null;
   104                 }
   105                 return cv.visitField(access, name, desc, signature, value);
   106             }
   108             @Override public void visitEnd() {
   109                 F f;
   110                 while ((f = fields.pollFirst()) != null) {
   111                     // Re-add dummy fields
   112                     cv.visitField(f.access, f.name, f.desc, f.signature, f.value);
   113                 }
   114             }
   116             private class F {
   117                 private int access;
   118                 private String name;
   119                 private String desc;
   120                 private String signature;
   121                 private Object value;
   122                 F(int access, String name, String desc, String signature, Object value) {
   123                     this.access = access;
   124                     this.name = name;
   125                     this.desc = desc;
   126                     this.signature = signature;
   127                     this.value = value;
   128                 }
   129             }
   130         }
   132         @Override public byte[] transform(ClassLoader loader, String className,
   133                 Class<?> classBeingRedefined,
   134                 ProtectionDomain protectionDomain, byte[] classfileBuffer)
   135             throws IllegalClassFormatException {
   137             if (className.contains("TypeAnnotatedTestClass")) {
   138                 try {
   139                     // Here we remove and re-add the dummy fields. This shuffles the constant pool
   140                     return asm(loader, className, classBeingRedefined, protectionDomain, classfileBuffer);
   141                 } catch (Throwable e) {
   142                     // The retransform native code that called this method does not propagate
   143                     // exceptions. Instead of getting an uninformative generic error, catch
   144                     // problems here and print it, then exit.
   145                     e.printStackTrace();
   146                     System.exit(1);
   147                 }
   148             }
   149             return null;
   150         }
   151     }
   153     private static void buildAgent() {
   154         try {
   155             ClassFileInstaller.main("RedefineAnnotations");
   156         } catch (Exception e) {
   157             throw new RuntimeException("Could not write agent classfile", e);
   158         }
   160         try {
   161             PrintWriter pw = new PrintWriter("MANIFEST.MF");
   162             pw.println("Premain-Class: RedefineAnnotations");
   163             pw.println("Agent-Class: RedefineAnnotations");
   164             pw.println("Can-Retransform-Classes: true");
   165             pw.close();
   166         } catch (FileNotFoundException e) {
   167             throw new RuntimeException("Could not write manifest file for the agent", e);
   168         }
   170         sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
   171         if (!jarTool.run(new String[] { "-cmf", "MANIFEST.MF", "redefineagent.jar", "RedefineAnnotations.class" })) {
   172             throw new RuntimeException("Could not write the agent jar file");
   173         }
   174     }
   176     public static void main(String argv[]) throws NoSuchFieldException, NoSuchMethodException {
   177         if (argv.length == 1 && argv[0].equals("buildagent")) {
   178             buildAgent();
   179             return;
   180         }
   182         if (inst == null) {
   183             throw new RuntimeException("Instrumentation object was null");
   184         }
   186         RedefineAnnotations test = new RedefineAnnotations();
   187         test.testTransformAndVerify();
   188     }
   190     // Class type annotations
   191     private Annotation classTypeParameterTA;
   192     private Annotation extendsTA;
   193     private Annotation implementsTA;
   195     // Field type annotations
   196     private Annotation fieldTA;
   197     private Annotation innerTA;
   198     private Annotation[] arrayTA = new Annotation[4];
   199     private Annotation[] mapTA = new Annotation[5];
   201     // Method type annotations
   202     private Annotation returnTA, methodTypeParameterTA, formalParameterTA, throwsTA;
   204     private void testTransformAndVerify()
   205         throws NoSuchFieldException, NoSuchMethodException {
   207         Class<TypeAnnotatedTestClass> c = TypeAnnotatedTestClass.class;
   208         Class<?> myClass = c;
   210         /*
   211          * Verify that the expected annotations are where they should be before transform.
   212          */
   213         verifyClassTypeAnnotations(c);
   214         verifyFieldTypeAnnotations(c);
   215         verifyMethodTypeAnnotations(c);
   217         try {
   218             inst.addTransformer(new Transformer(), true);
   219             inst.retransformClasses(myClass);
   220         } catch (UnmodifiableClassException e) {
   221             throw new RuntimeException(e);
   222         }
   224         /*
   225          * Verify that the expected annotations are where they should be after transform.
   226          * Also verify that before and after are equal.
   227          */
   228         verifyClassTypeAnnotations(c);
   229         verifyFieldTypeAnnotations(c);
   230         verifyMethodTypeAnnotations(c);
   231     }
   233     private void verifyClassTypeAnnotations(Class c) {
   234         Annotation anno;
   236         anno = c.getTypeParameters()[0].getAnnotations()[0];
   237         verifyTestAnn(classTypeParameterTA, anno, "classTypeParameter");
   238         classTypeParameterTA = anno;
   240         anno = c.getAnnotatedSuperclass().getAnnotations()[0];
   241         verifyTestAnn(extendsTA, anno, "extends");
   242         extendsTA = anno;
   244         anno = c.getAnnotatedInterfaces()[0].getAnnotations()[0];
   245         verifyTestAnn(implementsTA, anno, "implements");
   246         implementsTA = anno;
   247     }
   249     private void verifyFieldTypeAnnotations(Class c)
   250         throws NoSuchFieldException, NoSuchMethodException {
   252         verifyBasicFieldTypeAnnotations(c);
   253         verifyInnerFieldTypeAnnotations(c);
   254         verifyArrayFieldTypeAnnotations(c);
   255         verifyMapFieldTypeAnnotations(c);
   256     }
   258     private void verifyBasicFieldTypeAnnotations(Class c)
   259         throws NoSuchFieldException, NoSuchMethodException {
   261         Annotation anno = c.getDeclaredField("typeAnnotatedBoolean").getAnnotatedType().getAnnotations()[0];
   262         verifyTestAnn(fieldTA, anno, "field");
   263         fieldTA = anno;
   264     }
   266     private void verifyInnerFieldTypeAnnotations(Class c)
   267         throws NoSuchFieldException, NoSuchMethodException {
   269         AnnotatedType at = c.getDeclaredField("typeAnnotatedInner").getAnnotatedType();
   270         Annotation anno = at.getAnnotations()[0];
   271         verifyTestAnn(innerTA, anno, "inner");
   272         innerTA = anno;
   273     }
   275     private void verifyArrayFieldTypeAnnotations(Class c)
   276         throws NoSuchFieldException, NoSuchMethodException {
   278         Annotation anno;
   279         AnnotatedType at;
   281         at = c.getDeclaredField("typeAnnotatedArray").getAnnotatedType();
   282         anno = at.getAnnotations()[0];
   283         verifyTestAnn(arrayTA[0], anno, "array1");
   284         arrayTA[0] = anno;
   286         for (int i = 1; i <= 3; i++) {
   287             at = ((AnnotatedArrayType) at).getAnnotatedGenericComponentType();
   288             anno = at.getAnnotations()[0];
   289             verifyTestAnn(arrayTA[i], anno, "array" + (i + 1));
   290             arrayTA[i] = anno;
   291         }
   292     }
   294     private void verifyMapFieldTypeAnnotations(Class c)
   295         throws NoSuchFieldException, NoSuchMethodException {
   297         Annotation anno;
   298         AnnotatedType atBase;
   299         AnnotatedType atParameter;
   300         atBase = c.getDeclaredField("typeAnnotatedMap").getAnnotatedType();
   302         anno = atBase.getAnnotations()[0];
   303         verifyTestAnn(mapTA[0], anno, "map1");
   304         mapTA[0] = anno;
   306         atParameter =
   307             ((AnnotatedParameterizedType) atBase).
   308             getAnnotatedActualTypeArguments()[0];
   309         anno = ((AnnotatedWildcardType) atParameter).getAnnotations()[0];
   310         verifyTestAnn(mapTA[1], anno, "map2");
   311         mapTA[1] = anno;
   313         anno =
   314             ((AnnotatedWildcardType) atParameter).
   315             getAnnotatedUpperBounds()[0].getAnnotations()[0];
   316         verifyTestAnn(mapTA[2], anno, "map3");
   317         mapTA[2] = anno;
   319         atParameter =
   320             ((AnnotatedParameterizedType) atBase).
   321             getAnnotatedActualTypeArguments()[1];
   322         anno = ((AnnotatedParameterizedType) atParameter).getAnnotations()[0];
   323         verifyTestAnn(mapTA[3], anno, "map4");
   324         mapTA[3] = anno;
   326         anno =
   327             ((AnnotatedParameterizedType) atParameter).
   328             getAnnotatedActualTypeArguments()[0].getAnnotations()[0];
   329         verifyTestAnn(mapTA[4], anno, "map5");
   330         mapTA[4] = anno;
   331     }
   333     private void verifyMethodTypeAnnotations(Class c)
   334         throws NoSuchFieldException, NoSuchMethodException {
   335         Annotation anno;
   336         Executable typeAnnotatedMethod =
   337             c.getDeclaredMethod("typeAnnotatedMethod", TypeAnnotatedTestClass.class);
   339         anno = typeAnnotatedMethod.getAnnotatedReturnType().getAnnotations()[0];
   340         verifyTestAnn(returnTA, anno, "return");
   341         returnTA = anno;
   343         anno = typeAnnotatedMethod.getTypeParameters()[0].getAnnotations()[0];
   344         verifyTestAnn(methodTypeParameterTA, anno, "methodTypeParameter");
   345         methodTypeParameterTA = anno;
   347         anno = typeAnnotatedMethod.getAnnotatedParameterTypes()[0].getAnnotations()[0];
   348         verifyTestAnn(formalParameterTA, anno, "formalParameter");
   349         formalParameterTA = anno;
   351         anno = typeAnnotatedMethod.getAnnotatedExceptionTypes()[0].getAnnotations()[0];
   352         verifyTestAnn(throwsTA, anno, "throws");
   353         throwsTA = anno;
   354     }
   356     private static void verifyTestAnn(Annotation verifyAgainst, Annotation anno, String expectedSite) {
   357         verifyTestAnnSite(anno, expectedSite);
   359         // When called before transform verifyAgainst will be null, when called
   360         // after transform it will be the annotation from before the transform
   361         if (verifyAgainst != null) {
   362             assertTrue(anno.equals(verifyAgainst),
   363                        "Annotations do not match before and after." +
   364                        " Before: \"" + verifyAgainst + "\", After: \"" + anno + "\"");
   365         }
   366     }
   368     private static void verifyTestAnnSite(Annotation testAnn, String expectedSite) {
   369         String expectedAnn = "@TestAnn(site=" + expectedSite + ")";
   370         assertTrue(testAnn.toString().equals(expectedAnn),
   371                    "Expected \"" + expectedAnn + "\", got \"" + testAnn + "\"");
   372     }
   374     public static class TypeAnnotatedTestClass <@TestAnn(site="classTypeParameter") S,T>
   375             extends @TestAnn(site="extends") Thread
   376             implements @TestAnn(site="implements") Runnable {
   378         public @TestAnn(site="field") boolean typeAnnotatedBoolean;
   380         public
   381             RedefineAnnotations.
   382             @TestAnn(site="inner") TypeAnnotatedTestClass
   383             typeAnnotatedInner;
   385         public
   386             @TestAnn(site="array4") boolean
   387             @TestAnn(site="array1") []
   388             @TestAnn(site="array2") []
   389             @TestAnn(site="array3") []
   390             typeAnnotatedArray;
   392         public @TestAnn(site="map1") Map
   393             <@TestAnn(site="map2") ? extends @TestAnn(site="map3") String,
   394             @TestAnn(site="map4")  List<@TestAnn(site="map5")  Object>> typeAnnotatedMap;
   396         public int dummy1;
   397         public int dummy2;
   398         public int dummy3;
   400         @TestAnn(site="return") <@TestAnn(site="methodTypeParameter") U,V> Class
   401             typeAnnotatedMethod(@TestAnn(site="formalParameter") TypeAnnotatedTestClass arg)
   402             throws @TestAnn(site="throws") ClassNotFoundException {
   404             @TestAnn(site="local_variable_type") int foo = 0;
   405             throw new ClassNotFoundException();
   406         }
   408         public void run() {}
   409     }
   410 }

mercurial