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

Java 如何在运行时加载Jasper定制器类?,java,templates,jasper-reports,classloader,Java,Templates,Jasper Reports,Classloader,我需要用图表呈现Jasper报表,并需要为它们提供单独的ChartCustomizer类。我的应用程序以Java web应用程序的形式运行 当前状态是,模板(.jasper文件)与它们所需的资源打包在一个单独的jar文件中。这些jar文件本身作为BLOB存储在数据库中。我用自己的FileResolver加载它们,并将其作为参数提供给Jasper引擎 到目前为止,这对我来说非常有用,只是我不能加载我的定制器类。我尝试将它们放在另一个jar文件中,用自己的类加载器加载它们,并将其提供给Jasper引

我需要用图表呈现Jasper报表,并需要为它们提供单独的ChartCustomizer类。我的应用程序以Java web应用程序的形式运行

当前状态是,模板(.jasper文件)与它们所需的资源打包在一个单独的jar文件中。这些jar文件本身作为BLOB存储在数据库中。我用自己的FileResolver加载它们,并将其作为参数提供给Jasper引擎

到目前为止,这对我来说非常有用,只是我不能加载我的定制器类。我尝试将它们放在另一个jar文件中,用自己的类加载器加载它们,并将其提供给Jasper引擎:

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加载类是有效的


感谢您的帮助

好的,我发现我需要将类加载器放入当前线程的上下文中。我现在还使用匿名类加载器,以便只加载请求的类(还改进了调试)

// 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);