2014-01-09 25 views
0

我需要使用圖表呈現Jasper報表,並且需要單獨的ChartCustomizer類。我的應用程序以Java Web應用程序的形式運行。如何在運行時加載Jasper定製程序類?

當前狀態是,模板(.jasper文件)與其所需資源一起打包在單獨的jar文件中。這些jar文件本身作爲BLOB存儲在數據庫中。我用一個自己的FileResolver加載它們,我將它作爲Jasper引擎的一個參數提供。

到目前爲止,這對我很好,除非我無法加載我的Customizer類。我試圖把它們放在另一個jar文件,並用自己的ClassLoader加載它們,並提供給碧玉引擎:

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

好的,我發現我需要將類加載器放入當前線程的上下文中。我現在也在使用匿名類加載器,所以只有被請求的類纔會被加載(也改進了調試)。

// 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); 
相關問題