How to Set Classpath When I Use Javax.Tools.Javacompiler Compile the Source

How to set classpath when I use javax.tools.JavaCompiler compile the source?

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.

JavaCompiler classPath

You need to set the class path for the compile task.

Have a look at the answer over here:

  • How to set classpath when I use javax.tools.JavaCompiler compile the source?

How to set up classpath of JavaCompiler to multiple .jar files using wildcard

Wildcards: Since Java 1.6 wildcards are supported when using java/javaw/javac, more information: Windows/Solaris and Linux

example:

javac -cp "lib/*" Test.java

This uses all .jar files (not .class!) in the lib directory as classpath. This should not be confused with the *-expansion of your shell. -cp lib/* gets expanded to -cp lib/a.jar lib/b.jar which is not valid argument syntax. In order to avoid this you have to add quotation marks: -cp "lib/*"

The cause of your Problem: You are trying to call the Java compiler from source directly with its Java API. This source code does not contain the wildcard expansion.
The JDK ships with a wrapper binary (javac,javadoc,javah,javap are all the same binary) which does some things and finally calls the compiler task. This wrapper also expands the wildcards in your classpath and therefore the compiler task doesn't have to do this anymore (and it doesn't). See at Compiler Readme section "build -> Notes -> The launcher". Launcher sourcecode.

Solution:

  1. A very poor solution would be to call javac through a Processbuilder. (This is not recommended since it is a complicated and error prone solution for a simple problem)
  2. Expand the wildcards yourself:

example code:

String classpath = buildClassPath("lib/", "test/", "lib/*");
System.out.println(classpath);
// output: lib/;test/;lib/a.jar;lib/b.jar;

This function takes all classpath entries and builds one classpath. Classpath entries with a wildcard in it will get expanded.

/**
* This function builds a classpath from the passed Strings
*
* @param paths classpath elements
* @return returns the complete classpath with wildcards expanded
*/
private static String buildClassPath(String... paths) {
StringBuilder sb = new StringBuilder();
for (String path : paths) {
if (path.endsWith("*")) {
path = path.substring(0, path.length() - 1);
File pathFile = new File(path);
for (File file : pathFile.listFiles()) {
if (file.isFile() && file.getName().endsWith(".jar")) {
sb.append(path);
sb.append(file.getName());
sb.append(System.getProperty("path.separator"));
}
}
} else {
sb.append(path);
sb.append(System.getProperty("path.separator"));
}
}
return sb.toString();
}

Compile code fully in memory with javax.tools.JavaCompiler

I've run the above code in Mac OS Java 7. None of them works. So i wrote one
https://github.com/trung/InMemoryJavaCompiler

StringBuilder source = new StringBuilder()
.append("package org.mdkt;\n")
.append("public class HelloClass {\n")
.append(" public String hello() { return \"hello\"; }")
.append("}");

Class<?> helloClass = InMemoryJavaCompiler.compile("org.mdkt.HelloClass", source.toString());

Compile Circular Dependency classes using javax.tools.JavaCompiler

I have found a solution for the problem,

in the compilation process I have made a ArrayList to hold the SimpleJavaFileObject (classes to compile) instances, instead I have added a LinkedList.

with the link list it works fine :)



Related Topics



Leave a reply



Submit