title: how to retransform a class at runtime
body: <p>I am tring modify class which already loaded in a jvm. The solution which I found is:</p>
  
  <ul>
  <li>1st Attach an agent to a jvm specified by pid. (e.g. 8191)(Codes: AttachTest)</li>
  <li>2nd Find the class which you want modified from those that have already been loaded in the jvm(e.g. 8191).</li>
  <li>3rd Add transformer using Instrument (Codes: AgentMain)</li>
  <li>4th Modify the class(e.g. Person) in <code>transform</code> method(Codes: DemoTransformer)</li>
  <li>5th Retransform the class using <a href="https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html#RetransformClasses" rel="noreferrer">retransformClasses</a></li>
  </ul>
  
  <p>It works fine from 1st step to 5th step, but there are problems at <code>retransformClasses</code>. It called <code>transform</code> again which contains codes to modify class. And It modify other classes which I never wanna modify.
  I think the problem may occured during <code>addTransformer</code> or <code>retransformClasses</code>. But I still confused. Well, how to retransform a class? Any ideas? thx</p>
  
  <pre><code>public class AttachTest {
      public static void main(String[] args) throws AttachNotSupportedException,
          IOException, AgentLoadException, AgentInitializationException { 
          String agentPath = "D:\\work\\workspace\\myjar\\loaded.jar";
          String vid = args[0]; 
          VirtualMachine vm = VirtualMachine.attach(vid);
          vm.loadAgent(agentPath);
      }
  }
  </code></pre>
  
  <p>//Agent</p>
  
  <pre><code>public class AgentMain {
      public static void agentmain (String agentArgs, Instrumentation inst)
          throws ClassNotFoundException, UnmodifiableClassException,
          InterruptedException {
      Class&lt;?&gt; [] allLoadedClasses = inst.getAllLoadedClasses();
          String tmpString = null;
          for (int i = 0; i&lt;allLoadedClasses.length; i++) {
          tmpString = allLoadedClasses[i].getName();
  
  
          if (0 != tmpString.length()) {
              if (-1 != tmpString.lastIndexOf(".")) {
                  tmpString = tmpString.substring(tmpString.lastIndexOf(".")+1,tmpString.length());
              }
              if (tmpString.equals("Person")) {
  
                  inst.addTransformer(new DemoTransformer(), true);
                  inst.retransformClasses(allLoadedClasses[i]);
  
                  }
              }
          }
      }
  }
  </code></pre>
  
  <p>|</p>
  
  <pre><code>public class DemoTransformer implements ClassFileTransformer {
  
      @Override
      public byte[] transform (ClassLoader loader, String className,
          Class&lt;?&gt; classBeingRedefined, ProtectionDomain protectionDomain,
          byte[] classfileBuffer) throws IllegalClassFormatException {
  
      ModifyMethodTest tm = new ModifyMethodTest(classfileBuffer);
  
      byte[] byteArray = null;
      try {
          byteArray = tm.modiySleepMethod();
  
      } catch (Exception e) {
  
          e.printStackTrace();
      }
  
  
      return byteArray;
      }
  }
  </code></pre>
  
  <p><strong>OUTPUTS:</strong>
  <strong><em>THE ATTACH PROGRAM</em></strong></p>
  
  <pre><code>javax.management.RuntimeMBeanException: java.lang.RuntimeException: Failed to transform [Person]
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.rethrow(DefaultMBeanServerInterceptor.java:856)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.rethrowMaybeMBeanException(DefaultMBeanServerInterceptor.java:869)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:838)
      at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
      at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1427)
      at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:72)
      at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1265)
      at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1360)
      at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:788)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
      at sun.rmi.transport.Transport$1.run(Transport.java:159)
      at java.security.AccessController.doPrivileged(Native Method)
      at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
      at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
      at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
      at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
      at java.lang.Thread.run(Thread.java:619)
      at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
      at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
      at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
      at com.sun.jmx.remote.internal.PRef.invoke(Unknown Source)
      at javax.management.remote.rmi.RMIConnectionImpl_Stub.invoke(Unknown Source)
      at javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.invoke(RMIConnector.java:993)
      at AttachStackOverflow.main(AttachStackOverflow.java:57)
  Caused by: java.lang.RuntimeException: Failed to transform [Person]
      at loaded3.TransformerService.transform(TransformerService.java:75)
      at loaded3.TransformerService.transformClass(TransformerService.java:38)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:93)
      at com.sun.jmx.mbeanserver.StandardMBeanIntrospector.invokeM2(StandardMBeanIntrospector.java:27)
      at com.sun.jmx.mbeanserver.MBeanIntrospector.invokeM(MBeanIntrospector.java:208)
      at com.sun.jmx.mbeanserver.PerInterface.invoke(PerInterface.java:120)
      at com.sun.jmx.mbeanserver.MBeanSupport.invoke(MBeanSupport.java:262)
      at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:836)
      at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:761)
      at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1427)
      at javax.management.remote.rmi.RMIConnectionImpl.access$200(RMIConnectionImpl.java:72)
      at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1265)
      at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1360)
      at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:788)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:597)
      at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:305)
      at sun.rmi.transport.Transport$1.run(Transport.java:159)
      at java.security.AccessController.doPrivileged(Native Method)
      at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
      at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
      at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
      at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
      at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
      at java.lang.Thread.run(Thread.java:619)
  Caused by: java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
      at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
      at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:124)
      at loaded3.TransformerService.transform(TransformerService.java:72)
      ... 31 more
  </code></pre>
  
  <p><strong>OUTPUTS:</strong> <em>TARGET PROGRAM</em></p>
  
  <pre><code>print Call sayHello()
  print Hello World!
  Supported Redefine
  Supported Retransform
  Call transform() in TransformerService
  Add transformer
  support redefine. return TRUE
  support retransforme. return TRUE
  IsModifiable class "class Person". return TRUE
  Retransform classes
  Number of times to Call transform() in DemoTransformer:1
  ####ASM CODE####
  consturct ModifyMethodTest
  Call modifySleepMethod
  new classreader
  new classwriter
  construct ModifyClassAdapter
  sayHello
  consturct Modifymethod
  [arg1] = java/io/PrintStream  [arg2] = println  #5
  [arg1] = java/io/PrintStream  [arg2] = println  #13
  [arg1] = java/util/concurrent/TimeUnit  [arg2] = sleep  #22
  [arg1] = java/io/PrintStream  [arg2] = println  #30
  sayHello2
  consturct Modifymethod
  [arg1] = java/io/PrintStream  [arg2] = println  #5
  [arg1] = java/io/PrintStream  [arg2] = println  #13
  &lt;init&gt;
  consturct Modifymethod
  [arg1] = java/lang/Object  [arg2] = &lt;init&gt;  #1
  main
  consturct Modifymethod
  [arg1] = Person  [arg2] = &lt;init&gt;  #4
  [arg1] = Person  [arg2] = sayHello  #9
  [arg1] = Person  [arg2] = sayHello2  #13
  [arg1] = java/lang/InterruptedException  [arg2] = printStackTrace  #21
  getName
  consturct Modifymethod
  setName
  consturct Modifymethod
  Call visitend
  Finished to call modifymethodtest
  ####End of ASM CODE
  Remove transformer
  Call transform() in TransformerService
  Add transformer
  support redefine. return TRUE
  support retransforme. return TRUE
  IsModifiable class "class Person". return TRUE
  Retransform classes
  Number of times to Call transform() in DemoTransformer:2
  ####ASM CODE####
  consturct ModifyMethodTest
  Call modifySleepMethod
  new classreader
  new classwriter
  construct ModifyClassAdapter
  sayHello
  consturct Modifymethod
  [arg1] = java/io/PrintStream  [arg2] = println  #5
  [arg1] = java/io/PrintStream  [arg2] = println  #13
  [arg1] = java/util/concurrent/TimeUnit  [arg2] = sleep  #22
  [arg1] = java/io/PrintStream  [arg2] = println  #30
  sayHello2
  consturct Modifymethod
  [arg1] = java/io/PrintStream  [arg2] = println  #5
  [arg1] = java/io/PrintStream  [arg2] = println  #13
  &lt;init&gt;
  consturct Modifymethod
  [arg1] = java/lang/Object  [arg2] = &lt;init&gt;  #1
  main
  consturct Modifymethod
  [arg1] = Person  [arg2] = &lt;init&gt;  #4
  [arg1] = Person  [arg2] = sayHello  #9
  [arg1] = Person  [arg2] = sayHello2  #13
  [arg1] = java/lang/InterruptedException  [arg2] = printStackTrace  #21
  getName
  consturct Modifymethod
  setName
  consturct Modifymethod
  Call visitend
  Finished to call modifymethodtest
  ####End of ASM CODE
  Remove transformer
  print in sayHello()
  print Call sayHello2()
  print Hello World!2
  </code></pre>