Re: Problem recompile with new class definition

122 views
Skip to first unread message

Peter Lawrey

unread,
Dec 4, 2016, 12:30:06 PM12/4/16
to syafri...@students.itb.ac.id, java-ch...@googlegroups.com
Hello Syafri,
   You can't change a class definition after it was been loaded this way. You could do it by usin Instrumentation however we don't support that option.
The simplest way to do this is to create a ClassLoader each time you want to load a new version.

I have cc-ed the Java Chronicle group as this is where we answer questions for free and the answer may be useful for others.

Regards, Peter. 

On 4 Dec 2016 13:17, <syafri...@students.itb.ac.id> wrote:
Dear Peter Lawrey,

My name is Mohamad Syafri Tuloli, i am trying to use your openHFT/java-runtime-compiler to improve my mutation testing tools,
which currently use disk access to read and compiled mutated source code and this takes a long time.

Im wondering if you could help me with my problem using the code, the code works well, but when i try to recompile a class 
(the class have new definition) the class reference still use the previous definition.

The output from code below was:
123
123

the second line of output was suppose to be 234, since the TheClass.callme() implementation was modified.
Below are my part of my code, the complete code are attached.

//Previous Definiton  of the class
StringBuilder firstSrc = new StringBuilder();
firstSrc.append("package eko;\n");
firstSrc.append("public class TheClass {\n");
firstSrc.append(" public String callme() {\n");
firstSrc.append(" System.out.println(\"123\" );");
firstSrc.append(" return \"abcd\";\n");
firstSrc.append(" }\n");
firstSrc.append("}\n"); 

Class testClass = CompilerUtils.CACHED_COMPILER.loadFromJava(
getClass().getClassLoader(), "eko.TheClass", firstSrc.toString());
Object testObject = testClass.newInstance();
Method testMethod = testClass.getDeclaredMethod("callme", new Class[]{});
testMethod.invoke(testObject, null);  

//new definition of the class
StringBuilder srcUpdated = new StringBuilder();
srcUpdated.append("package eko;\n");
srcUpdated.append("public class TheClass {\n");
srcUpdated.append(" public String callme() {\n");
srcUpdated.append(" System.out.println(\"234\" );");
srcUpdated.append(" return \"abcd\";\n");
srcUpdated.append(" }\n");
srcUpdated.append("}\n");

Class newClass = CompilerUtils.CACHED_COMPILER.loadFromJava(
getClass().getClassLoader(), "eko.TheClass", srcUpdated.toString());
Object newObject = newClass.newInstance();
Method newMethod = newClass.getDeclaredMethod("callme", new Class[]{});
newMethod.invoke(newObject, null);

Sincerely,
Syafri
--
Mohamad Syafri Tuloli
Institut Teknologi Bandung
Indonesia

Mohamad Tuloli

unread,
Dec 5, 2016, 4:46:24 AM12/5/16
to Chronicle
It works, Thanks Peter.

--
Syafri

Mohamad Tuloli

unread,
Dec 22, 2016, 3:09:57 AM12/22/16
to Chronicle, syafri...@students.itb.ac.id
I have implement Peter Lawrey suggestion and its works well, under a condition that, the new class definition must be the first class that loaded to the classloader, for example:

A : a class which definition will be revised (mutated)
B : other class that will never be changed.

My program will be work if the call sequence was load A then B like below

for( somecondition){
     String ASourceCode = mutation();  //some operation of generation/manipulation/mutation of ASourceCode
     ClassLoader classLoader = new ClassLoader() { };
     Class AClass = CompilerUtils.CACHED_COMPILER.loadFromJava( classLoader, "A" , ASourceCode);
     Class BClass = CompilerUtils.CACHED_COMPILER.loadFromJava( classLoader, "B" , BSourceCode);
}

In that sequence, the AClass will be referenced to the new definition (source code) each time loaded (each iteration)

but if the load sequence was B then A, (because class A may need class B to compile), the AClass was still using the first loaded definition of class A, and will never be changed to its newly generated definition (source code).

I first suspect that i can make it work by commenting line 18-19  from loadFromJava class from your library (attached picture), so each time loading a class, it will recompile the class and other previously loaded class within the same classloader (which sacrifice efficiency), but it turn out giving a wrong result.

      //  if (clazz != null)
       //     return clazz;

Thank you very much for all your help.


Reply all
Reply to author
Forward
0 new messages