All right, this one isn't exactly exiting, but while working on Py4J, I encountered the following problem (that had to be solved in Java):
- Given a simple name, return a list of fully qualified names accessible at runtime.
- In other words, implement the auto-import feature available in popular Java IDEs,
- but at runtime. For example, given
List, you should return
[java 1="java.awt.List" language=".util.List,"][/java].
- Classpath: get a list of all the directories and jars passed in the classpath, inspect these jars/directories and return a list of packages.
- Bootstrap: get a list of all the directories and jars used to load the JVM (e.g., rt.jar containing java.lang, java.util, etc.), inspect these jars/directories and return a list of packages.
- Current classloader: get a list of all available packages in the current classloader (i.e.,
Package.getPackages(). This could be useful to detect dynamically generated classes created with cglib or Javassist.
- Eclipse: assuming that you are in an Eclipse plug-in and that you can access all plug-ins (i.e.,
Eclipse-BuddyPolicy: global), get a list of all plug-ins in an Eclipse installation and then, get a list of exported packages for each plug-in.
I had no idea how to do this, so I asked a question on stackoverflow, but to my dismay, the only answers I got were "it can't be done". It hurts because one of the commenters was an expert in classloading/reflection issues on StackOverflow. Still, I wanted a best effort solution (not a 100% accurate one) and in a general programming language like Java, "it can't be done" is not an acceptable answer.
If you want to skip to the code directly, be my guest. Otherwise, read on to learn more about the solution!
My journey thus began and I read a lot about traversing classloaders, inspecting the classpath, looking at the content of a jar file, getting a list of packages available in a classloader, and so on. A simple solution would have been to get a list of all classes available in each classloader. A classloader is an object that is responsible for loading the definition of a class (e.g., when you write
Unfortunately, I quickly reached the conclusion that any solution would have to be extensible and that there was no general solution. It is not possible in Java to traverse and inspect all classloaders, even if a classloader will eventually load a class you need. This means that a best-effort solution would just try to load a fully qualified name to know if it is accessible (e.g., try to call
Class.forName("java.util.List")). The problem then became: How can I get a list of accessible packages at runtime?
To solve this problem, I created a series of
PackageProvider. These are classes responsible for getting a list of accessible packages in specific environment. These are the package providers I implemented:
And that's it. It's horribly slow on large Eclipse installations, but it works like a charm. With some caching, the speed becomes tolerable. Other package providers could be created for environments like a web container (e.g., Tomcat, JBoss). Don't hesitate to look at the code, it's available under the new BSD license.