Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic compilation with provided ClassLoader #64

Closed
tioricardo opened this issue Aug 21, 2018 · 14 comments
Closed

Dynamic compilation with provided ClassLoader #64

tioricardo opened this issue Aug 21, 2018 · 14 comments

Comments

@tioricardo
Copy link

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.

@lukaseder
Copy link
Member

Thank you very much for your suggestion. That definitely makes sense. Will implement right away.

@lukaseder
Copy link
Member

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?

@tioricardo
Copy link
Author

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)

@lukaseder
Copy link
Member

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?

@tioricardo
Copy link
Author

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().

@lukaseder
Copy link
Member

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?

@tioricardo
Copy link
Author

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.

@lukaseder
Copy link
Member

By "it" I meant CXF.

Oh, I see, thanks for clarifying! :-) That does make more sense indeed.

@tioricardo
Copy link
Author

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!

@lukaseder
Copy link
Member

Cool, thanks for the feedback. Glad you've found a solution

@lukaseder
Copy link
Member

Related: #72

@joanbonilla
Copy link

joanbonilla commented Nov 27, 2018

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

@lukaseder
Copy link
Member

@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.

@joanbonilla
Copy link

You are right, I replaced the original package (I didn't want to show it :) ) #73

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants