I have a test class called "InnerClassTransactionServlet", inside that class I have defined an inner class called RandomResultHandler (InnerClassTransactionServlet$RandomResultHandler).

I am trying to redefine the inner class dynamically, but the instrumentation is returning "class names don't match" error:

java.lang.NoClassDefFoundError: class names don't match
    at sun.instrument.InstrumentationImpl.redefineClasses0(Native Method)
    at sun.instrument.InstrumentationImpl.redefineClasses(InstrumentationImpl.java:170)
    at com.example.Test.redefineClass(Test.java:33)
    .
    .
    .

I have tried to redefine also the enclosing class but I receive the same error.

The method in charge of the redefinition is very simple:

public static void redefineClass(ClassDefinition definition) throws ClassNotFoundException, UnmodifiableClassException{
        log.debug("Trying to redefine class "+definition.getDefinitionClass().getName());
        Agent.getInstrumentation().redefineClasses(definition);
}

The "definition" parameter is just a ClassDefinition object defined with the class name and the byte result of the compilation:

log.debug("Class "+clazz.getName()+" compiled properly. Trying to replace the bytecode in memory.");
ClassDefinition cd = new ClassDefinition(clazz, compilationResult);
redefineClass(cd);

Using exactly the same code to redefine not nested classes (or classes without nested classes) it works fine.

Do you know if it is possible to redefine nested classes or classes that encloses nested classes?

Thanks!!

1

There are 1 answers

0
mrt On

Finally I've been able to find the issue :)

It is necessary to redefine the nested classes at the same time than the enclosing one. It is not possible to redefine just the nested class.

So, I have changed my redefinition method to receive multiple ClassDefinition objects:

public static void redefineClasses(ClassDefinition... definition) throws ClassNotFoundException, UnmodifiableClassException{
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < definition.length; i++) {
            if ( sb.length() > 0 )
                sb.append(", ");
            sb.append(definition[i].getDefinitionClass().getName());
        }

        log.debug("Trying to redefine class"+(definition.length>1?"es ":" ")+sb);
        Agent.getInstrumentation().redefineClasses(definition);
    }

So, now for redefine my inner class I am calling that method with the class definition of "InnerClassTransactionServlet" and "InnerClassTransactionServlet$RandomResultHandler" and the code is properly replaced.