如何在运行时加载Jasper定制器类?

时间:2014-01-09 14:30:15

标签: java templates jasper-reports classloader

我需要使用图表呈现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的类加载工作。

感谢任何帮助!

1 个答案:

答案 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);