[英]How to load classes from a .war file and use them?
我有一個項目正在生成一個.war
文件作為構建工件。 我想將此.war
加載到 JVM 中,以便解析它包含的運行時注釋,但在加載類時遇到問題。
我有以下代碼片段從JarFile
獲取類名:
public static Set<String> getClassNamesFromJarFile(JarFile jarFile) throws IOException {
Set<String> classNames = new HashSet<>();
Enumeration<JarEntry> e = jarFile.entries();
while (e.hasMoreElements()) {
JarEntry jarEntry = e.nextElement();
if (jarEntry.getName().endsWith(".class")) {
String className = jarEntry.getName()
.replace("/", ".");
className = className.substring(0, className.length() - 6);
classNames.add(className);
}
}
return classNames;
}
我使用這個片段來獲取JarFile
:
protected static JarFile getJarFile(String jarFileUrl) throws IOException {
try {
return new JarFile(new URI(jarFileUrl.replaceAll(" ", "%20")).getSchemeSpecificPart());
} catch (URISyntaxException ex) {
return new JarFile(jarFileUrl.substring("file:".length()));
}
}
然后,在我的主要部分,我有以下代碼:
public static void main(String[] args) throws IOException {
String warpath = "C:\\User\\Me\\Desktop\\someWarFile.war";
// Fetch JarFile
JarFile jar = getJarFile("file:" + warpath);
// Load .war into the JVM
URL url = new File(warpath).toURI().toURL();
URLClassLoader child = new URLClassLoader(
new URL[]{url},
Object.class.getClassLoader()
);
// Get class names in the .war
Set<String> classes = getClassNamesFromJarFile(jar);
// Try to get classes from name
for (String className : classes) {
try {
System.out.println("CLASS FOUND: " + className);
Class<?> actualClass= Class.forName(className, true, child);
} catch(Error | Exception e) {
System.out.println("ERROR: " + e);
}
}
}
對於每個類,我都會得到輸出:
...
CLASS FOUND: WEB-INF.classes.com.some.company.project.state.ProjectStateProvider$1
ERROR: java.lang.NoClassDefFoundError: com/some/company/project/state/ProjectStateProvider$1 (wrong name: WEB-INF/classes/com/some/company/project/state/ProjectStateProvider$1)
CLASS FOUND: WEB-INF.classes.com.some.company.configuration.rest.JsonProvider
ERROR: java.lang.NoClassDefFoundError: com/some/company/configuration/rest/JsonProvider (wrong name: WEB-INF/classes/com/some/company/configuration/rest/JsonProvider)
...
我試過刪除WEB-INF.
和WEB-INF.classes.
來自類名的前綴,我也嘗試將.class
添加到類名和以前解決方案的每個組合中,但我只得到一個java.lang.ClassNotFoundException
。
如何引用從.war
加載的類,例如WEB-INF.classes.com.some.company.project.state.ProjectStateProvider$1
類?
我現在更新了代碼。 它現在在 .war 文件中找到相應的類文件。
現在會出現的問題是,如果要加載一個依賴於其他尚未加載的類的類。
所以你可以
代碼:
package stackoverflow;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
public class JarLoading {
public static void main(final String[] args) throws MalformedURLException, IOException {
final String fileName = "D:\\upload\\K4D-Prozesstafel.war";
final File file = new File(fileName);
reloadWar(file);
}
static private void reloadWar(final File pJarFile) throws MalformedURLException, IOException {
System.out.println("JarLoading.reloadJar() " + pJarFile);
final String defaultPattern = "jar:file:" + pJarFile + "!/WEB-INF/classes/";
// final URL oldURL = pJarFile.toURI().toURL();
final URL newURL = new URL(defaultPattern);
System.out.println("DP:\t" + defaultPattern);
try (final URLClassLoader classLoader = new URLClassLoader(new URL[] { newURL }); //
final JarFile file = new JarFile(pJarFile);) {
final Enumeration<JarEntry> entries = file.entries();
while (entries.hasMoreElements()) {
final JarEntry jarEntry = entries.nextElement();
if (!isClassFile(jarEntry)) {
continue;
}
try {
final String id = getClassName(jarEntry);
System.out.println("Loading file " + id);
final Class<?> cls = classLoader.loadClass(id);
System.out.println("\tLoaded file: " + cls);
} catch (final ClassNotFoundException e2) {
System.out.println("\tFile not a class file: " + jarEntry.getName() + "\n\t\t" + e2);
return;
}
}
// if (plugin.isValid()) mPlugins.add(plugin);
}
}
static private boolean isClassFile(final ZipEntry entry) {
return !entry.isDirectory() && entry.getName().endsWith(".class");
}
static private String getClassName(final ZipEntry entry) {
String className = entry.getName().replace('/', '.'); // including ".class"
className = className.substring(0, className.length() - ".class".length());
className = className.replace("WEB-INF.classes.", "");
return className;
}
}
現在這可能會導致異常,例如:
JarLoading.reloadJar() D:\upload\K4D-Prozesstafel.war
DP: jar:file:D:\upload\K4D-Prozesstafel.war!/WEB-INF/classes/
Loading file biz.k4d.gremienplaner.prozesstafel.cruds.BoxCRUD
Exception in thread "main" java.lang.NoClassDefFoundError: biz/cbsoft/lib/jee/glassfish/io/crud/TemplateCRUD_BaseEntity
因為類文件biz.k4d.gremienplaner.prozesstafel.cruds.BoxCRUD
現在已加載,但它依賴於另一個 jar 中的文件,即biz/cbsoft/lib/jee/glassfish/io/crud/TemplateCRUD_BaseEntity
。
好的。 我稍微改變了getClassNamesFromJarFile
方法:
public static Set<String> getClassNamesFromJarFile(
JarFile file, String pfx, String sfx) {
Set<String> result = new HashSet<>();
Enumeration<JarEntry> enm = file.entries();
while (enm.hasMoreElements()) {
JarEntry e = enm.nextElement();
String path = e.getName();
if (path.startsWith(pfx) && path.endsWith(sfx)) {
path = path.substring(pfx.length(), path.length()-sfx.length());
path = path.replace('/', '.');
result.add(path);
}
}
return result;
}
然后:
public static void main(String[] args) throws IOException {
String warpath = "C:\\User\\Me\\Desktop\\someWarFile.war";
// Fetch JarFile
JarFile jar = new JarFile(warpath);
// Load .war into the JVM
URL url = new URL("jar:file:" + warpath + "!/WEB-INF/classes/");
URLClassLoader child = new URLClassLoader(
new URL[]{url},
Object.class.getClassLoader()
);
// Get class names in the .war
Set<String> classes = getClassNamesFromJarFile(jar, "WEB-INF/classes/", ".class");
// Try to get classes from name
for (String className : classes) {
try {
System.out.println("CLASS FOUND: " + className);
Class<?> actualClass= Class.forName(className, true, child);
} catch(Error | Exception e) {
System.out.println("ERROR: " + e);
}
}
}
更新:
現在,如果類依賴於不在類路徑中的其他類,它們將不會加載。 例如,如果 war 包含 WEB-INF/lib 中的 jar 文件,則需要將它們添加到URLClassLoader
中。 您還應該提供 servlet API 的 jar。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.