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 wroteList<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:
- 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) - 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
Javafx Using Objects from Maincontroller or Other Controllers in Proper Controller Class
Reserved Words as Names or Identifiers
Java - Convert Image to Base64
Create a Jtds Connection String
Please Explain About Insertable=False and Updatable=False in Reference to the JPA @Column Annotation
How to Convert a Byte Array to Its Numeric Value (Java)
Exception Starting Filter Struts2 - Tried Adding Jar'S, But Same Result
How to Print Escape Characters in Java
Multiple Runnable Classes Inside Jar, How to Run Them
Bufferedimage Not Being Cleared Before Each Rendering
Problem with Assigning an Array to Other Array in Java
Performance of Stringtokenizer Class VS. String.Split Method in Java
Why Do I Get "Non-Static Variable This Cannot Be Referenced from a Static Context"
Selenium Webdriver + Java - Eclipse: Java.Lang.Noclassdeffounderror