The main thing is that when the class loader loads the classes, javac will call JavaFileManager#list() to get a list of all the files in the package.
Therefore, to use a custom classloader, you need to modify (or extend) it to override JavaFileManager#list() . We hope you can reuse some of the logic used to load classes.
You can use native JavaFileObject implementations to represent class objects. Then you need to override JavaFileManager#inferBinaryName() (otherwise a javac version error will be JavaFileManager#inferBinaryName() ). Your JavaFileObject implementations JavaFileObject also override (at least) JavaFileObject#openInputStream .
Here are a few pointers: http://atamur.blogspot.be/2009/10/using-built-in-javacompiler-with-custom.html
Also, don't make your life harder than you need, and extend the ForwardingJavaFileManager and SimpleJavaFileObject .
For reference, here is an example implementation:
@Override public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException { Iterable<JavaFileObject> stdResults = fileManager.list(location, packageName, kinds, recurse); if (location != StandardLocation.CLASS_PATH || !kinds.contains(JavaFileObject.Kind.CLASS)) { return stdResults; } Set<JavaFileObject> additional = pkgObjects.get(packageName); if (additional == null || additional.isEmpty()) { return stdResults; } List<JavaFileObject> out = new ArrayList<>(); for (JavaFileObject obj : additional) { out.add(obj); } for (JavaFileObject obj : stdResults) { out.add(obj); } return out; }
Where pkgObjects is a map from package names to JavaFileObject . The way you fill out this map depends on how your class loader works.
source share