String CompilePath = \"abc.java\";
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
String classpath = System.getProperty(\"java.class.path\");
System.s
You cannot depend on java.class.path to be set to anything in particular.
Java establishes this variable when it launches the entire JVM containing your servlet container. As it creates many different class loaders for many different other purposes, it does not change it. It cannot. There is only one value of java.class.path for the entire process, but there can be many different webapps, and indeed many different class loaders inside each webapp.
You will need your own explicit configuration mechanism to communicate the class path for this sort of compilation stuff, and to use getRealPath to construct the pathnames.
Assuming you are using ANT to build your WAR file. You need to do something like below to include jars under WEB-INF/lib in your WAR. Modify the directory structure as it fits your app directory structure.
<war warfile="yourApp.war" webxml="WEB-INF/web.xml">
<fileset dir="yourWarDir">
<include name="**/*.jsp"/>
<include name="**/include/**"/>
</fileset>
<include name="WEB-INF/lib/*"/>
<include name="WEB-INF/classes/**"/>
</war>
They way you are setting the java.class.path system property is asking for trouble - better not do that. More elegant approach would be to use the -classpath
option to pass in the custom classpath. See How do I use JDK6 ToolProvider and JavaCompiler with the context classloader? for details.
Also this question can be useful reference: Using javax.tools.ToolProvider from a custom classloader?
As to building the actual classpath, you could cast the context classloader to URLClassLoader
and get files from those URLs (as done in this answer).
Or you could use ServletContext.getRealPath(String)
and build the entire classpath by hand:
ServletConfig cfg = ...; //obtained in Servlet.init(ServletConfig) method
ServletContex ctx = cfg.getServletContext();
String realWebInfPath = ctx.getRealPath("WEB-INF/lib");
//TODO use the realWebInfPath to create a File object and iterate over all JAR files
Warning: both approaches ONLY work if web application is expanded (not WAR file). If it is not expanded, you are out of luck.
So, my question is how do I make the compiler refer to the jar files from the WEB-INF/lib directory?
Provide that the webapp's WAR is expanded, you should be able to programmatically create a classpath string that corresponds to what the web container gives you. It is "simply" a matter of duplicating the effective class search path that the web container uses.
However, I suspect that passing a "classpath" argument to the compiler, explicitly or via the System properties is the wrong approach. I found the following in this IBM article.
Compiling Java source requires the following components:
- A classpath, from which the compiler can resolve library classes. The compiler classpath is typically composed of an ordered list of file system directories and archive files (JAR or ZIP files) that contain previously compiled .class files. The classpath is implemented by a JavaFileManager that manages multiple source and class JavaFileObject instances and the ClassLoader passed to the JavaFileManager constructor. ...
So it would seem that the correct approach is to just grab the relevant classloader object and pass it to the JavaFileManager constructor.