IntelliJ Idea tomcat Hot swap failed: schema change not implemented Operation not supported by VM

biesczadka picture biesczadka · Jan 16, 2015 · Viewed 13.5k times · Source

I got this error when I try to reload class (hot swap) with changed method bodies in my project. Before everything works fine, but suddenly it stop and I don't remember nothing what could be a cause. What is strange I have another project with the same setting and hot swap for method bodies works fine.

Here is configuration for NOT-working project:

enter image description here

enter image description here

And my VM settings:

-XX:PermSize=512m
-XX:MaxPermSize=1024m
-Xms1024m
-Xmx2048m
-Dcatalina.home="C:\Programy\apache-tomcat-7.0.57"
-Djava.endorsed.dirs="C:\Programy\apache-tomcat-7.0.57\endorsed"
-javaagent:C:\Programy\apache-tomcat-7.0.57/lib/spring-instrument-3.1.2.RELEASE.jar
-Dspring.profiles.active=closeMonthTest
-Dnpk.jobs.enabled=true

and here is configuration for my working project:

enter image description here

enter image description here

VM options:

-XX:PermSize=512m
-XX:MaxPermSize=1024m
-Xms1024m
-Xmx2048m
-Dcatalina.home="C:\Programy\apache-tomcat-7.0.57"
-Djava.endorsed.dirs="C:\Programy\apache-tomcat-7.0.57\endorsed"
-javaagent:C:\Programy\apache-tomcat-7.0.57/lib/spring-instrument-3.1.2.RELEASE.jar
-Dspring.profiles.active=test

Answer

Ivan Mamontov picture Ivan Mamontov · Jan 17, 2015

It is very difficult to find the root cause without code. However, I can write an artificial test case where the Java compiler will create synthetic methods even if I just change a method body:

public class Test {

    static class Inner {

        private void getPrivate(int i) {
            Thread.dumpStack();
        }

        private void getPrivate() {
            Thread.dumpStack();
        }
    }

    public static void main(String[] args) {
        Inner inner = new Inner();
        inner.getPrivate(0);
        inner.getPrivate();
    }
}

This effect is explained by a synthetic method access$000 which javac generates to allow access to a private member of the Inner class.

javac Test.java 
javap -c -private Test\$Inner
  ...
  static void access$000(edu.Test$Inner, int);
    Code:
       0: aload_0       
       1: iload_1       
       2: invokespecial #2                  // Method getPrivate:(I)V
       5: return        

  static void access$100(edu.Test$Inner);
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method getPrivate:()V
       4: return        

Let's change the order of two methods in the main:

    public static void main(String[] args) {
        Inner inner = new Inner();
        inner.getPrivate();
        inner.getPrivate(0);
    }

As a result the compiler has changed methods signatures.

  ...
  static void access$000(edu.Test$Inner);
    Code:
       0: aload_0       
       1: invokespecial #2                  // Method getPrivate:()V
       4: return        

  static void access$100(edu.Test$Inner, int);
    Code:
       0: aload_0       
       1: iload_1       
       2: invokespecial #1                  // Method getPrivate:(I)V
       5: return     

From HotSwap point of view this change is prohibited because signature of method access$000 was changed.