System.getProperty("java.class.path") не показывает "WEB-INF/lib" и включающие jar
String CompilePath = "abc.java";
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
String classpath = System.getProperty("java.class.path");
System.setProperty("java.class.path", classpath + ";" + LocalMachine.home + "WebContent/WEB-INF/lib");
int result = compiler.run(null, null, null, CompilePath);
Вышеуказанное работает нормально, когда выполняется как тест JUnit, так как все jars
требуется для составления abc.java
файл. Но когда тот же код выполняется в качестве сервера, он не может найти требуемый jar
файлы. Выход из System.getProperty("java.class.path")
является E:\apache-tomcat-7.0.4\bin\bootstrap.jar;E:\apache-tomcat-7.0.4\bin\tomcat-juli.jar;C:\Program Files\Java\jdk1.6.0_21\lib\tools.jar
Итак, мой вопрос: как заставить компилятор обращаться к файлам jar из каталога WEB-INF/lib?
4 ответа
То, как вы устанавливаете системное свойство java.class.path, вызывает проблемы - лучше не делать этого. Более элегантный подход будет использовать -classpath
возможность передать в пользовательский путь к классу. См. Как использовать JDK6 ToolProvider и JavaCompiler с загрузчиком классов контекста? для деталей.
Также этот вопрос может быть полезной ссылкой: Использование javax.tools.ToolProvider из пользовательского загрузчика классов?
Что касается построения фактического пути к классам, вы можете привести контекстный загрузчик классов к URLClassLoader
и получить файлы с этих URL-адресов (как сделано в этом ответе).
Или вы можете использовать ServletContext. getRealPath(String)
и создайте весь путь к классам вручную:
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
Предупреждение: оба подхода работают ТОЛЬКО, если веб-приложение развернуто (не WAR-файл). Если он не расширен, вам не повезло.
Вы не можете зависеть от java.class.path, который будет установлен на что-то конкретное.
Java устанавливает эту переменную, когда запускает всю JVM, содержащую ваш контейнер сервлета. Так как он создает много разных загрузчиков классов для многих других целей, он не меняет его. Это не может. Для всего процесса существует только одно значение java.class.path, но в каждом веб-приложении может быть много разных веб-приложений и даже много разных загрузчиков классов.
Вам понадобится ваш собственный явный механизм конфигурации, чтобы сообщить путь к классу для такого рода вещей компиляции и использовать getRealPath для создания путей.
Итак, мой вопрос: как заставить компилятор обращаться к файлам jar из каталога WEB-INF/lib?
При условии, что WAR веб-приложения расширен, вы должны иметь возможность программно создать строку пути к классу, которая соответствует тому, что дает вам веб-контейнер. Это просто вопрос дублирования эффективного пути поиска классов, который использует веб-контейнер.
Однако я подозреваю, что передача аргумента "classpath" в компилятор явно или через свойства System является неправильным подходом. Я нашел следующее в этой статье IBM.
Компиляция исходного кода Java требует следующих компонентов:
- Путь к классам, из которого компилятор может разрешать библиотечные классы. Путь к классам компилятора обычно состоит из упорядоченного списка каталогов файловой системы и архивных файлов (файлов JAR или ZIP), которые содержат ранее скомпилированные файлы.class. Путь к классам реализуется JavaFileManager, который управляет несколькими экземплярами исходного кода и класса JavaFileObject, а ClassLoader передается в конструктор JavaFileManager....
Поэтому может показаться, что правильный подход - просто взять соответствующий объект загрузчика классов и передать его конструктору JavaFileManager.
Предполагая, что вы используете ANT для создания файла WAR. Вам нужно сделать что-то подобное ниже, чтобы включить jar-файл под WEB-INF/lib в вашу WAR. Измените структуру каталогов так, как она соответствует структуре каталогов вашего приложения.
<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>