44

I use the class javax.tools.JavaCompiler (jdk6) to compile a source file, but the source file depends on some jar file. How to set the classpath of the javax.tools.JavaCompiler?

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
Diablo.Wu
  • 1,151
  • 5
  • 15
  • 17

3 Answers3

42

The javax.tools.JavaCompiler#getTask() method takes an options parameter that allows to set compiler options. The following message describes an easy way to set them in order to access the calling program's classpath:

You need to configure the standard java file manager to know about the jar files(s) - you use the compiler options argument to do that.

By default the java compiler object only seems to know about the default locations for bootclasspath, extdirs and endorseddirs directories in terms of its classpath.

You need to add the calling program's current classpath to the java compiler instance's which gets passed on the the standard file manager, which will then find classes in the jar files.

Here's how I do it in the compiler wrapper I wrote

List<String> optionList = new ArrayList<String>();
// set compiler's classpath to be same as the runtime's
optionList.addAll(Arrays.asList("-classpath",System.getProperty("java.class.path")));

// any other options you want
optionList.addAll(Arrays.asList(options));

JavaCompiler.CompilationTask task = compiler.getTask(out,jfm,diagnostics,optionList,null,jfos);

All you'll need then is to get the proper classpath set when running the calling program.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Satheesh posted this as an answer, "Would you be able to share your compiler wrapper( link does not work) thanks in advance." – Kirk Woll May 30 '12 at 16:50
  • thanks a mill for this post, ive been struggling with this for ages and this was the answer... cheers :) – flexinIT Jul 27 '12 at 16:43
  • 2
    BTW, `classpath` option of `JavaCompiler` doesn't "understand" wildcards. So each `jar` you have to add directly in this string. – Andremoniy Mar 06 '15 at 11:15
  • The solution provided in [this blog post](http://atamur.blogspot.de/2009/10/using-built-in-javacompiler-with-custom.html) helped me a lot. It doesn't work with setting the classpath via an option property. It implements a custom file manager to load classes from an existing classloader (e.g. a web application classloader). – Michael Ernst Jun 01 '16 at 22:04
  • This also helped me a lot. I'm setting up a complicated JUnit in my Maven project, where I'm creating .java files on the fly. Wanted a way to inherit the current classpath, and then add a bit. The answer is obvious really ;), but I wasn't sure it'd work inside Maven, inside Eclipse. – cs94njw Sep 07 '16 at 09:10
5

The same problem occurred to me recently, finally I found two workarounds. You can set the class path either by invoke StandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, "YOUR_CLASS_PATH") or Compiler.getTask(ARG_0, ARG_1, ARG_2, CLASS_PATH_OPTIONS, just as the first answer posted here says.

deadshot
  • 8,881
  • 4
  • 20
  • 39
Vince.Wu
  • 870
  • 1
  • 10
  • 17
  • 2
    To get this to work I needed to do `StandardJavaFileManager.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(new File(classpath)));` – John Dorian Feb 19 '15 at 20:06
0

I needed something simpler than the examples above.

The following is a self-contained example of using the built-in Java compiler, and setting the classpath for the compiler to use.

It is equivalent to creating a source file called HelloPrinter.java and then compiling it as follows:

javac -classpath C:\Users\dab\Testing\a.jar;c:\path\etc org\abc\another\HelloPrinter.java

Note how the classpath can be set using a String[] of options. This should be familiar if you're already used to running javac on the command line (as above).

This code is compatible with Java 6. You will need a JDK, not a JRE, for this to run. This example doesn't actually use the classpath. It all does is print "Hello". You can add an import statement to the generated source and call a method in an external Jar file to test this properly.

import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;

public class JavaCompilerExample {
    
    public static void main(String[] args) throws Exception {

        String className = "HelloPrinter";
        String directoryName = "org/abc/another";
        new File(directoryName).mkdirs();

        FileOutputStream fos = new FileOutputStream(directoryName+"/"+className+".java");
        PrintStream ps = new PrintStream(fos);
        ps.println(
                "package "+directoryName.replace("/", ".")  + " ; "
                + "public class " +className + 
                "{ public static void main(String[] args){System.out.println(\"Hello\");} }");
        ps.close();
        
        JavaCompiler javac = ToolProvider.getSystemJavaCompiler();
        String javacOpts[] = {"-classpath", 
                             "C:\\Users\\dab\\Testing\\a.jar;c:\\path\\etc;",
                              directoryName+"/"+className + ".java"};
        
        if ( javac.run(null, null, null,  javacOpts)!=0 ) {
            System.err.println("Error");
            System.exit(1);
        }
        
        
    }

}
DAB
  • 1,631
  • 19
  • 25