Jump to content
Changes to the Jaspersoft community edition download ×

How to load a Jasper customizer class during runtime?


toffer
Go to solution Solved by toffer,

Recommended Posts

I need to render Jasper reports with charts and require individual ChartCustomizer classes for them. My application is running as a Java web-application.

Current state is, that the templates (.jasper files) are packaged with their required resources in a separate jar-file. These jar files themselves are stored as BLOBs in the Database. I load them with an own FileResolver, which I provide as a parameter to the Jasper Engine.

So far this works great for me, except I cannot load my Customizer classes. I tried to put them in another jar file and load them with an own ClassLoader and also provide that to the 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);[/code]

but I am still getting a java.lang.ClassNotFoundException, although I can see in the Debugger, that the classloading from jar works.

Any help is appreciated!

 

Link to comment
Share on other sites

  • Replies 1
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

  • Solution

Ok, I figured out that I need to put the class loader into the current thread's context. I am also using an anonymous class loader now, so that only requested classes get loaded (also improves debugging).

             // 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);[/code]

 

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...