Class AnonymousClassPatchPlugin


  • @Plugin(name="AnonymousClassPatch",
            description="Swap anonymous inner class names to avoid not compatible changes.",
            testedVersions="DCEVM")
    public class AnonymousClassPatchPlugin
    extends Object
    Class names MyClass$1, MyClass$2 are created in the order as anonymous class appears in the source code. After anonymous class insertion/deletion the indexes are shifted producing not compatible hot swap.

    This patch will create class state info before the change (from current ClassLoader via reflection) and after the change (from filesystem using javassist) find all compatible transitions.

    For example if you exchange order the anonymous class appears in the source code, Transition may produce something like:

    • MyClass$1 -> MyClass$2
    • MyClass$2 -> MyClass$3
    • MyClass$3 -> MyClass$1
    Then the transformation will behave:
    • When the class MyClass$1 is hot swapped, the bytecode from MyClass$2 is returned (and renamed to MyClass$1)
    • When the class MyClass$2 is hot swapped, the bytecode from MyClass$3 is returned (and renamed to MyClass$2)
    • When the class MyClass$3 is hot swapped, the bytecode from MyClass$1 is returned (and renamed to MyClass$3)
    • When the class MyClass is hot swapped, all occurences of MyClass$1 are exchanged for MyClass$3
    • , all occurences of MyClass$2 are exchanged for MyClass$1
    • , all occurences of MyClass$3 are exchanged for MyClass$2

    Swap may produce even to not compatible change. Consider existing MyClass$1 and MyClass$2, then MyClass$1 is removed. Then hotswap is called only on MyClass$1, which contains different class to MyClass$2. Then MyClass$1 is on hotswap replaced with empty implementation and new class MyClass$1000x is created to contain code from the new MyClass$1 (class compatible with old MyClass$2). Not that because this is not a true hotswap, old existing instances of MyClass$1 are updated to an empty class, not the new one. When calling a method on this class, AbstractErrorMethod is thrown (this should be replaced to some more clear error in the future).

    Author:
    Jiri Bubnik