Dynamic compilation with provided ClassLoader
tioricardo opened this issue · 14 comments
Hi, is it possible to create overloaded Compile.compile(String, String, ClassLoader)
and Reflect.compile(String, String, ClassLoader)
?
I use Apache CXF to create dynamic SOAP web service client, but it loads the classes on a new ClassLoader instance, so I can't reference them on my class compiled by Reflect.compile(String, String)
.
I may try submit a PR later.
Thank you very much for your suggestion. That definitely makes sense. Will implement right away.
Hang on, I misunderstood. Would you mind showing an example of what doesn't work with the current implementation, and how your suggestion would improve that?
To create a dynamic SOAP client, Apache CXF reads a WSDL, generates Java source files and then creates a new ClassLoader to load the classes.
When I call the service, I need to use an instance of one of those classes.
I intend to use jOOR to compile a java.util.function.Function to populate the request object, but it needs the ClassLoader created by CXF to load the class.
Currently I can't compile my class, the error I get is:
Exception in thread "main" org.joor.ReflectException: Compilation error: /ricardo/sandbox/Input2Request.java:5: error: package com.dataaccess.webservicesserver does not exist
com.dataaccess.webservicesserver.NumberToWords req = new com.dataaccess.webservicesserver.NumberToWords();
^
/ricardo/sandbox/Input2Request.java:5: error: package com.dataaccess.webservicesserver does not exist
com.dataaccess.webservicesserver.NumberToWords req = new com.dataaccess.webservicesserver.NumberToWords();
^
2 errors
at org.joor.Compile.compile(Compile.java:65)
at org.joor.Reflect.compile(Reflect.java:77)
at ricardo.sandbox.Sample.joor(Sample.java:64)
at ricardo.sandbox.Sample.main(Sample.java:21)
Oh, I see, thanks for the explanation. But are you sure that passing a class loader is really needed? It appears that it might be sufficient to simply pass the desired parent class loader to the ClassLoader
constructor.
I have created a branch:
https://github.com/jOOQ/jOOR/tree/issue-64
With a fix:
aac2e98
Would you mind testing that on your side to see if it fixes your problem?
I just reviewed your fix and I realized I didn't mention I'm working with Java 8. My bad m(._.)m
Anyway, CXF uses org.apache.cxf.common.classloader.ClassLoaderUtils.getURLClassLoader()
to get a ClassLoader:
public static ClassLoader getURLClassLoader(
final URL[] urls, final ClassLoader parent
) {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return new URLClassLoader(urls, parent);
}
});
}
with parent
as Thread.currentThread().getContextClassLoader()
, so it's not related to the MethodHandles.lookup().lookupClass().getClassLoader()
.
Huh, but you also said:
but it loads the classes on a new ClassLoader instance
And that's being done in the Java 9+ distribution only. Maybe I really do need an MCVE first before I can help here: https://stackoverflow.com/help/mcve
Or you could send a PR that you know will fix your issue?
but it loads the classes on a new ClassLoader instance
By "it" I meant CXF.
Right now I'm at work, later I'll provide an MCVE.
Thanks for all the replies.
By "it" I meant CXF.
Oh, I see, thanks for clarifying! :-) That does make more sense indeed.
I prepared an MCVE, but when I tested with a possible fix a new problem arose.
The class that I tried to compile was referencing a dynamic class that exists only in memory, so I couldn't set a classpath with it.
So instead of new com.dataaccess.webservicesserver.NumberToWords()
I used org.joor.Reflect.on("com.dataaccess.webservicesserver.NumberToWords", cl)
and it worked as intended.
Thanks for your help!
Cool, thanks for the feedback. Glad you've found a solution
Hi,
I have a spring boot application with some custom code and I've tried to compile that sample with a custom class:
Supplier<String> supplier = Reflect.compile(
"com.sample.soc.RuntimeCompilerTest",
"package com.sample.soc; " +
"import com.sample.package.WebsitesBO; " +
"class RuntimeCompilerTest implements java.util.function.Supplier<String> { " +
"public String get() { " +
"return \"Hello World!\"; } " +
"}"
).create().get();
But I get the next error (classloader):
Compilation error: /com/sample/soc/RuntimeCompilerTest.java:1: error: package com.sample.package does not exist\r\npackage com.sample.soc; import com.sample.package.WebsitesBO; class RuntimeCompilerTest implements java.util.function.Supplier { public String get() { return "Hello World!"; } }\r\n ^\r\n1 error\r\n
Can I compile dynamic classes with my custom code?
Thank you.
Java 8
Library Version: 0.9.8 and 0.9.9
@joanbonilla May I invite you to create a new issue in the future? Yours isn't really related to this one. In your case, you named a package package
, which is not possible in Java, given that package
is a reserved word.
You are right, I replaced the original package (I didn't want to show it :) ) #73