Search code examples
javaweblogicjava-6

How to set up the context class loader's classpath for runtime compilation?


I would like to compile and load new classes at runtime within a weblogic 10.3 server. Class loading seems to be somewhat straightforward:

class ClassFileManager 
extends ForwardingJavaFileManager<StandardJavaFileManager> {

  Map<String, JavaClassObject> classes = new HashMap<String, JavaClassObject>();

  public ClassFileManager(StandardJavaFileManager standardManager) {
    super(standardManager);
  }

  @Override
  public ClassLoader getClassLoader(Location location) {
    return new SecureClassLoader(currentThread().getContextClassLoader()) {
      @Override
      protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] b = classes.get(name).getBytes();
        return super.defineClass(name, b, 0, b.length);
      }
    };
  }

  @Override
  public JavaFileObject getJavaFileForOutput(
      Location location, String className, Kind kind, FileObject sibling)
      throws IOException {
    JavaClassObject result = new JavaClassObject(className, kind);
    classes.put(className, result);
    return result;
  }
}

The simplest way to perform class loading seems to be to initialise a SecureClassLoader and have it use the contextClassLoader as the parent.

But when setting up the -classpath option for the JDK's runtime compiler, I cannot seem to find a "context classpath" in a string form. The following is a bit of a hack that works "well enough":

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
ClassFileManager fileManager = 
    new ClassFileManager(compiler.getStandardFileManager(null, null, null));
List<String> options = new ArrayList<String>();
options.add("-classpath");
options.add(System.getProperty("java.class.path") + ";" +
    getClass().getProtectionDomain()
              .getCodeSource().getLocation()
              .toURI().toString()
              .replace("file:/", "").replace("/", "\\"));

But it doesn't generate the complete class path of the context class loader. How can I do it, reliably? Can I?


Solution

  • WebLogic 10.3.6 has a fairly complex ClassLoader implementation. Fortunately the classloader used for web applications exposes a getClassPath method.

    ClassLoader cl = Thread.currentThread().getContextClassLoader();
    String classPath = ((weblogic.utils.classloaders.GenericClassLoader)cl).getClassPath();
    
    // Once we have a classpath it's standard procedure
    JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
    StandardJavaFileManager sfm = compiler.getStandardFileManager(null, null, null);
    List<String> optionList = new ArrayList<String>();
    optionList.addAll(Arrays.asList("-classpath", classPath));
    compiler.getTask(null, sfm, null, optionList, null, sources).call();