2014-01-09 5 views
0

Мне нужно отображать отчеты Jasper с диаграммами и для них требуются отдельные классы ChartCustomizer. Мое приложение работает как веб-приложение Java.Как загрузить класс настройки Jasper во время выполнения?

Текущее состояние состоит в том, что шаблоны (файлы .jasper) упакованы с их необходимыми ресурсами в отдельный файл jar. Эти файлы jar сами хранятся как BLOB в базе данных. Я загружаю их собственным FileResolver, который я предоставляю в качестве параметра Jasper Engine.

До сих пор это отлично работает для меня, за исключением того, что я не могу загрузить классы Customizer. Я пытался поставить их в другой файл фляги и загружать их с собственным 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, хотя я могу видеть в Debugger, который работает с загрузкой классов из 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); 
Смежные вопросы