Skip to main content

add custom classloaders to compilation classpath

6 replies [Last post]
mpocock
Offline
Joined: 2006-02-13
Points: 0

Anyone who has written java bytecode generators has probably written a custom classloader to expose that bytecode, allowing it to be generated and loaded within a running VM. This sort of stuff is very common when writing bridges to expose non-java code to a java application e.g. exposing objective-c to java where the objective-c classes are only known at bind-time, or when generating systematically-named utility classes (pair_object_object, pair_object_int, tripple_int_int_double and so on).

However, currently there is no way to load these custom classloaders into the classpath that javac will compile code against. This means that we have to have a multi-phaze build:

1) process the source to work out what dynamically generated classes it will use

2) use the custom class-loader to make these classes and write them out

3) include these classes in the classpath, compile the source

4) load the custom class-loader classes from the compiled source and run the app

If we could tell javac to add custom classloaders, then this would change to:

1) javac -custom_class_loader my.custom.ClassLoaderImpl theSource.java

2) - see 4) above

The only potential down-side I can see to this is that if the custom class loader is not the same between the compilation and running steps then the symbols won't resolve, but that's not realy any different to using a different version of a .jar lib for compile and run-time.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
dmytro_sheyko
Offline
Joined: 2005-12-19
Points: 0

Could
[pre]
javac -J-Djava.system.class.loader=my.custom.ClassLoaderImpl theSource.java
[/pre]
help you?

mpocock
Offline
Joined: 2006-02-13
Points: 0

Brilliant! Thanks. Amazing what you never see in the docs :-)

garyh
Offline
Joined: 2003-06-20
Points: 0

I also appreciate the post, as we were looking to do the same thing and I also hadn't seen the comment in the docs.

But I ran into 2 problems. First of all, javac could not find my custom classloader. I solved this problem relatively easily by changing my "-classpath" argument to "-Jclasspath" as in the following:

[code] javac -J-Djava.system.class.loader=my.custom.ClassLoaderImpl -J-classpath -J%CUSTOM_CLASSLOADER_CLASSPATH% theSource.java [/code]

However, I then ran into my second problem. Javac was clearly using my custom classloader for the core Java classes (java.lang.String, com.sun.tools.javac.Main were loaded), but it was not using my custom classloader for applcation classes. Instead, I would get messages on System.out that my application classes could not be found. I suspect the problem is that javac doesn't use my custom classloader to resolve dependendencies, but rather uses its own resource finder with the "-classpath" argument as the location of resources. I could set the "-classpath" argument, but that defeats the whole purpose of the custom classloader.

Any thoughts?

dmytro_sheyko
Offline
Joined: 2005-12-19
Points: 0

Yes, you're right.

Mustang Beta javac supports direct annotation processing. Perhaps it would be helpful for your tasks.

garyh
Offline
Joined: 2003-06-20
Points: 0

My custom classloader is pretty trivial. It just extends URLClassLoader and dynamically determines the URLs of the jars to use as the classpath. This allows us to develop and maintain mulitiple standalone java apps and web apps with different dependencies and keep all of our jars in one place, including multiple vesions of the same jars (appropriately named of course.) Since we are using Ant to compile, I was planning on writing a custom task to set a property with the desired classpath,, and then just using the javac task with the property as the classpath.

Out of curiosity, however, how do you know that I am right about javac. Upon reflection, it seems clear to me that the java environment running the javac program is distinct from the javac program itself, and that therefore the custom classloader is not used at all, but I am only using logical assertions. Have you found this documented anywhere (I couldn't), or have you looked at the source code (I have not)?

Thank you very much.

subanark
Offline
Joined: 2004-11-26
Points: 0

Its pretty clear that javac doesn't use the classloader to resolve dependencies when compiling classes. If it did, then it would end up loading thoes classes into memory and the classes would be linked, meaning that the static block () of each resolved class would execute, which would be bad. Without modifing any of suns classes the most you could do is allow a preprocessor, which one project does by defining a new charset.