Как загрузить класс apach xmlbeans с помощью загрузчика классов? - PullRequest
0 голосов
/ 14 октября 2018

У нас есть приложение для составления отчетов, которое по умолчанию генерирует выходные данные в формате pdf, но вы можете написать свои собственные классы для создания любого другого выходного формата.Таким образом, я сгенерировал xls файлы, используя apache poi 10.0.Но теперь пришел запрос на создание файла xlsx.Когда я пытаюсь создать книгу с этим кодом:

XSSFWorkbook wbTemplate=new XSSFWorkbook()

Я получил ошибку:

java.lang.NoSuchMethodError: org.apache.xmlbeans.XmlOptions.setSaveAggressiveNamespaces()Lorg/apache/xmlbeans/XmlOptions;

Я обнаружил, что приложение уже использует очень старую версию файла xmlbeansэто, конечно, не содержит вышеуказанный метод.Сначала я попытался заменить файл XML-компонента новой версией на случай, если мне повезет, но приложение зависнет.

Моя следующая идея - использовать classLoader и когда приложение запускает мой класс для генерации файла xlsx.Я загружаю вышеупомянутый метод.Для этого я реализовал это решение, найденное в Интернете:

URL[] classLoaderUrls = new URL[]{new URL("file:/C:/HOME/Installs/Apache POI/poi-3.10/ooxml-lib/xmlbeans-2.6.0.jar")};
URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls);
Class<?> beanClass = urlClassLoader.loadClass("org.apache.xmlbeans.XmlOptions");
Constructor<?> constructor = beanClass.getConstructor();
Object beanObj = constructor.newInstance();
Method[] m=beanClass.getMethods();
Method method = beanClass.getMethod("setSaveAggressiveNamespaces");
method.invoke(beanObj);

Но каково удивление, когда он хочет получить имя метода "setSaveAggressiveNamespaces", я снова получил ошибку, что эта функция не существует.Затем я записал в файл все имена функций этого класса, и это правда, что это имя не существует.Но существует еще один, называемый setSaveAggresiveNamespaces, с одним S!Если я вызываю это, это работает, но, конечно, когда я не хочу создавать книгу XSSF, я все равно получаю сообщение о том, что setSaveAggressiveNamespaces (с двойным SS) не существует.Но setSaveAggressiveNamespaces должен быть в классе, так как он идет с пакетом apache poi.

Что я могу сделать в этом случае, чтобы он работал?Приложение работает под Java 1.6

Заранее спасибо за ответы.

ОБНОВЛЕНИЕ

Аксель, вот как яТеперь загрузите класс:

 public void customClassLoader() throws Exception
{
    URL[] classLoaderUrls = new URL[]{new URL("file:/C:/HOME/Installs/Apache POI/poi-3.10/ooxml-lib/xmlbeans-2.3.0.jar")};
    URLClassLoader urlClassLoader = new URLClassLoader(classLoaderUrls,null);
    Class<?> beanClass = urlClassLoader.loadClass("org.apache.xmlbeans.XmlOptions");
    log("RESOURCES:" +beanClass.getResource("/org/apache/xmlbeans/XmlOptions.class"));
    Constructor<?> constructor = beanClass.getConstructor();
    Object beanObj = constructor.newInstance();
    Method[] m=beanClass.getMethods();
    for (int i=0;i<m.length;++i)
        log("QQQ:" +String.valueOf(i)+".: "+ m[i].getName());
    Method method = beanClass.getMethod("setSaveAggressiveNamespaces");
    method.invoke(beanObj);
}

И затем я вызываю вышеупомянутую функцию в первой строке класса, который генерирует отчет.Перед ним ничего нет.

Ресурс записывается в журнал как: "РЕСУРСЫ: jar: file: / C: / HOME / Installs / Apache POI / poi-3.10 / ooxml-lib / xmlbeans-2.3.0.jar! /org/apache/xmlbeans/XmlOptions.class "

1 Ответ

0 голосов
/ 14 октября 2018

URLClassLoader (java.net.URL []) состояния:

Создает новый URLClassLoader для указанных URL-адресов с использованием родительского делегата по умолчанию ClassLoader .

Таким образом, родительский объект делегирования по умолчанию также будет использоваться ClassLoader, и поэтому org.apache.xmlbeans.XmlOptions будет загружен оттуда, если найден, а не из дополнительных данных URL.

Такнам нужно , а не с использованием родительского делегирования по умолчанию ClassLoader. URLClassLoader (java.net.URL [], null) делает это.

Пример:

import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Constructor;

public class UseURLClassLoader {

 public static void main(String[] args) throws Exception {
  URL[] classLoaderUrls;
  URLClassLoader urlClassLoader;
  Class<?> beanClass;

  classLoaderUrls = new URL[]{new URL("file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/ooxml-lib/xmlbeans-2.6.0.jar")};
  urlClassLoader = new URLClassLoader(classLoaderUrls); //default delegation parent ClassLoader is used
  beanClass = urlClassLoader.loadClass("org.apache.xmlbeans.XmlOptions");
System.out.println(beanClass.getResource("/org/apache/xmlbeans/XmlOptions.class")); //class is loaded using default parent class loader

  URL context = new URL("file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/");
  classLoaderUrls = new URL[] {
   new URL(context, "poi-3.10.1-20140818.jar"),
   new URL(context, "poi-ooxml-3.10.1-20140818.jar"),
   new URL(context, "poi-ooxml-schemas-3.10.1-20140818.jar"),
   // maybe others also necessary
   new URL(context, "lib/commons-codec-1.5.jar"),
   // maybe others also necessary
   new URL(context, "ooxml-lib/xmlbeans-2.6.0.jar")
   // maybe others also necessary
  };
  for (int i = 0; i < classLoaderUrls.length; i++) {
System.out.println(classLoaderUrls[i]);
  }
  urlClassLoader = new URLClassLoader(classLoaderUrls, null); //set default parent class loader null
  beanClass = urlClassLoader.loadClass("org.apache.xmlbeans.XmlOptions");
System.out.println(beanClass.getResource("/org/apache/xmlbeans/XmlOptions.class")); //class is loaded using this class loader

 }

}

Для меня вызывается следующим образом:

axel@arichter:~/Dokumente/JAVA/poi/poi-4.0.0$ java -cp .:./*:./lib/*:./ooxml-lib/* UseURLClassLoader 

выдает:

jar:file:/home/axel/Dokumente/JAVA/poi/poi-4.0.0/ooxml-lib/xmlbeans-3.0.1.jar!/org/apache/xmlbeans/XmlOptions.class
file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/poi-3.10.1-20140818.jar
file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/poi-ooxml-3.10.1-20140818.jar
file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/poi-ooxml-schemas-3.10.1-20140818.jar
file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/lib/commons-codec-1.5.jar
file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/ooxml-lib/xmlbeans-2.6.0.jar
jar:file:/home/axel/Dokumente/JAVA/poi/poi-3.10.1/ooxml-lib/xmlbeans-2.6.0.jar!/org/apache/xmlbeans/XmlOptions.class

Итак, сначала класс загружается с использованием загрузчика родительского класса по умолчанию.Для меня это загружает org.apache.xmlbeans.XmlOptions дальше от более нового xmlbeans-3.0.1.jar.Для вас он загружается дальше от старого xmlbeans-1.*.jar.Это связано с тем, что эти файлы находятся в пути к классу загрузчика родительского класса по умолчанию.

Вторая часть кода устанавливает нулевой загрузчик родительского класса по умолчанию, поэтому класс загружается только с использованием этого загрузчика классов.

Но возиться с загрузчиками классов - это беспорядок.Как подразумевается в моем коде, если для родительского загрузчика классов по умолчанию установлено значение null, нам нужно предоставить текущему загрузчику классов все необходимые исходные классы.Это часто становится очень дорогим.Так что не , если старые jar в пути к классам всегда будут лучшим решением, чем возиться с загрузчиками классов.

...