免责声明:我知道有很多关于类加载的问题,但我还没有找到解决方案......
我的类路径中有一个类,它依赖于动态加载的类。现在我可以在 java 8 上加载该类,但在更高版本上这是一个问题。
在我的类路径上,我有 c:/git/udevelop91/JAVA/usoft.jar
其中包含 com.usoft.birt.ReportEngine
类。为了让这个类工作,我需要 c:/ReportEngine/lib
中的 jars。这些 jar 之一包含 PlatformConfig。当我单独加载平台配置时,它工作正常并且类得到解析。然而,当我尝试加载 ReportEngine 类时,失败了。因为它依赖于LibraryClassLoader中的platformconfig。我也将 usoft.jar 添加到 LibraryClassLoader 中,看看是否有效,但似乎它一直使用 AppClassLoader 而不是我的 LibraryClassLoader,从而导致 NoClassDefFoundError
。如何在不从类路径中删除 usoft.jar 且不将所有 birt jar 添加到类路径中的情况下解决此问题?因此带有 reportEngineInst
的行失败
public void loadIt(){
File f = new File("C:/ReportEngine/lib");
File[] files = f.isDirectory() ? f.listFiles() : new File[] {f};
URL[] urlss = new URL[files.length];
int i = 0;
for(File ff : files){
urlss[i++] = ff.toURI().toURL();
}
LibraryClassLoader urlloader = new LibraryClassLoader(urlss, ClassLoader.getSystemClassLoader());
urlloader.addJar("c:/git/udev/JAVA/USoft.jar");
Class<?> platformLoader = Class.forName("org.eclipse.birt.core.framework.PlatformConfig",true,urlloader);
Class<?> report = urlloader.loadClass("com.usoft.birt.ReportEngine");
// ---------- The line below fails with a NoClassDefFoundError ----------
Object reportEngineInst = report.getDeclaredConstructor(String.class, String.class).newInstance("c:/ReportEngine", "c:/ReportEngine");
}
public class LibraryClassLoader extends URLClassLoader{
public LibraryClassLoader( URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public void addJar(String path) throws MalformedURLException {
super.addURL(Paths.get(path).toUri().toURL());
}
}
最佳答案
Simon 的评论帮助我意识到我无法使用 SystemClassLoader。为了继续在类路径上使用具有相同类的当前解决方案,并稍后添加特定类,我现在拥有:
public void loadIt() throws Exception{
/*Instantiate list for own classloader*/
ArrayList<URL> urlss = new ArrayList<>();
/*First fix the default classpath dependencies. usoft.jar is normally on the classpath*/
for(String pathEntry : System.getProperty("java.class.path").split(System.getProperty("path.separator"))) {
File fPathEntry = new File(pathEntry);
File[] fPathEntries = fPathEntry.isDirectory() ? fPathEntry.listFiles() : new File[] {fPathEntry};
for(File f : fPathEntries)
urlss.add(f.toURI().toURL());
}
/*Now add the specific stuff*/
File f = new File("C:/ReportEngine/lib");
File[] files = f.isDirectory() ? f.listFiles() : new File[] {f};
for(File ff : files)
urlss.add(ff.toURI().toURL());
/*
Make the classloader with the PlatformClassLoader as a parent
instead of the SystemClassLoader. I tried without a parent
classloader, but then you cant find the platform classes
like java.sql.*
*/
URLClassLoader urlloader = new URLClassLoader(urlss.toArray(new URL[urlss.size()]), ClassLoader.getPlatformClassLoader());
/*And now it magically works*/
Class<?> platformLoader = Class.forName("org.eclipse.birt.core.framework.PlatformConfig",true,urlloader);
Class<?> report = Class.forName("com.usoft.birt.ReportEngine",true,urlloader);
Object a = report.getDeclaredConstructor(String.class, String.class).newInstance("c:/reportEngine", "c:/reportEngine") ;
Method m = report.getMethod("generateDOC", String.class, String.class, Object[].class);
m.invoke(a,"","",new Object[] {});
}
关于java - NoClassDefFoundError - 动态加载类路径类依赖项在 URLClassLoader 中加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58912324/