Override nested class at runtime, is it possible? (java.lang.NoClassDefFoundError: class names do not match)
I have a test class called "InnerClassTransactionServlet", inside this class I have defined an inner class called RandomResultHandler (InnerClassTransactionServlet $ RandomResultHandler).
I'm trying to override an inner class dynamically, but the toolkit returns a "class names do not 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 tried to override the include class but I get the same error.
The method responsible for overriding 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 compilation result byte:
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 override non-nested classes (or classes without nested classes) it works great.
Do you know if it is possible to override nested classes or classes that contain nested classes?
Thank!!
source to share
Finally, I was able to find the problem :)
It is necessary to override nested classes at the same time except the attached one. It is not possible to override just a nested class.
So, I changed the redefinition method to get 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 to override my inner class, I call this method with the class definition "InnerClassTransactionServlet" and "InnerClassTransactionServlet $ RandomResultHandler" and the code has been replaced correctly.
source to share