toffer Posted January 9, 2014 Share Posted January 9, 2014 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 More sharing options...
Solution toffer Posted January 10, 2014 Author Solution Share Posted January 10, 2014 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 More sharing options...
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now