我需要使用图表呈现Jasper报告,并且需要单独的ChartCustomizer类。我的应用程序作为Java Web应用程序运行。
当前状态是,模板(.jasper文件)与其所需资源一起打包在一个单独的jar文件中。这些jar文件本身作为BLOB存储在数据库中。我使用自己的FileResolver加载它们,我将其作为Jasper Engine的参数提供。
到目前为止,这对我很有用,除了我无法加载我的Customizer类。我试着将它们放在另一个jar文件中并使用自己的ClassLoader加载它们并将它提供给Jasper Engine:
URL customizersUrl = classLoader.findResource("customizers.jar");
if (customizersUrl != null) {
URI jarUri = customizersUrl.toURI();
JarFile jarFile = new JarFile(new File(jarUri));
Enumeration e = jarFile.entries();
URL[] jarContentUrls = {new URL("jar:file:" + jarUri.getPath() + "!/")};
customizerClassLoader = URLClassLoader.newInstance(jarContentUrls);
while (e.hasMoreElements()) {
JarEntry je = (JarEntry) e.nextElement();
if (je.isDirectory() || !je.getName().endsWith(".class")) {
continue;
}
// -6 because of .class
String className = je.getName().substring(0, je.getName().length() - 6);
className = className.replace('/', '.');
Class c = customizerClassLoader.loadClass(className);
}
}
parameters.put(JRParameter.REPORT_CLASS_LOADER, customizerClassLoader);
但我仍然得到一个java.lang.ClassNotFoundException,虽然我可以在调试器中看到jar的类加载工作。
感谢任何帮助!
答案 0 :(得分:0)
好的,我发现我需要将类加载器放入当前线程的上下文中。我现在也在使用匿名类加载器,因此只加载请求的类(也改进了调试)。
// check if customizer classes are present and load them
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
final URL customizersUrl = classLoader.findResource("customizers.jar");
if (customizersUrl != null) {
ClassLoader cl = new ClassLoader() {
@Override
public Class loadClass(String className) throws ClassNotFoundException {
try {
return contextClassLoader.loadClass(className);
} catch (ClassNotFoundException ex) {
if (customizersUrl != null) {
try {
URI jarUri = customizersUrl.toURI();
URL[] jarContentUrls = {new URL("jar:file:" + jarUri.getPath() + "!/")};
URLClassLoader customizerInnerClassLoader = URLClassLoader.newInstance(jarContentUrls);
return customizerInnerClassLoader.loadClass(className);
} catch (URISyntaxException ex1) {
logger.debug("Exception during customizer class loading", ex1);
} catch (IOException ex1) {
logger.debug("Exception during customizer class loading", ex1);
} catch (ClassNotFoundException ex1) {
throw new ClassNotFoundException("Exception during customizer class loading", ex1);
}
}
}
return null;
}
};
// squeeze our own class loader in
Thread.currentThread().setContextClassLoader(cl);
}
byte[] result = generate(jasperReport, parameters);
// changing the class loader back to its origin... just to be safe
Thread.currentThread().setContextClassLoader(contextClassLoader);