1 /*
  2  * Copyright (c) 2024, 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  */
 23 
 24 /*
 25  * @test
 26  * @summary Test for value class retransformation
 27  *
 28  * @library /test/lib
 29  * @modules java.instrument
 30  * @enablePreview
 31  *
 32  * @run main RetransformValueClass buildAgent
 33  *
 34  * @run main/othervm -javaagent:testAgent.jar RetransformValueClass
 35  */
 36 
 37 import java.lang.instrument.Instrumentation;
 38 import java.lang.instrument.ClassFileTransformer;
 39 import java.security.ProtectionDomain;
 40 
 41 import jdk.test.lib.helpers.ClassFileInstaller;
 42 
 43 /*
 44  * The test verifies Instrumentation.retransformClasses() (and JVMTI function RetransformClasses)
 45  * works with value classes (i.e. JVMTI JvmtiClassFileReconstituter correctly restores class bytes).
 46  */
 47 
 48 value class ValueClass {
 49     public int f1;
 50     public String f2;
 51 
 52     public ValueClass(int v1, String v2) {
 53         f1 = v1;
 54         f2 = v2;
 55     }
 56 }
 57 
 58 public class RetransformValueClass {
 59 
 60     public static void main (String[] args) throws Exception {
 61         if (args.length == 1 && "buildAgent".equals(args[0])) {
 62             buildAgent();
 63         } else {
 64             runTest();
 65         }
 66     }
 67 
 68     static void buildAgent() throws Exception {
 69         String manifest = "Premain-Class: RetransformValueClass\nCan-Redefine-Classes: true\nCan-Retransform-Classes: true\n";
 70         ClassFileInstaller.writeJar("testAgent.jar", ClassFileInstaller.Manifest.fromString(manifest), "RetransformValueClass");
 71     }
 72 
 73     // agent implementation
 74     static Instrumentation instrumentation;
 75     public static void premain(String agentArgs, Instrumentation inst) {
 76         instrumentation = inst;
 77     }
 78 
 79     // test implementation
 80     static final Class targetClass = ValueClass.class;
 81     static final String targetClassName = targetClass.getName();
 82     static boolean transformToOriginalClassbytes = false;
 83 
 84     static void runTest() throws Exception {
 85         instrumentation.addTransformer(new Transformer(), true);
 86 
 87         instrumentation.retransformClasses(targetClass);
 88 
 89         transformToOriginalClassbytes = true;
 90         instrumentation.retransformClasses(targetClass);
 91     }
 92 
 93 
 94     static class Transformer implements ClassFileTransformer {
 95         public Transformer() {
 96         }
 97 
 98         public byte[] transform(ClassLoader loader, String className,
 99             Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
100 
101             if (className.equals(targetClassName)) {
102                 log("Transformer sees '" + className + "' of " + classfileBuffer.length + " bytes.");
103                 if (transformToOriginalClassbytes) {
104                     return classfileBuffer;
105                 } else {
106                     return  null;
107                 }
108             }
109             return null;
110         }
111     }
112 
113     static void log(Object o) {
114         System.out.println(String.valueOf(o));
115     }
116 }