为了账号安全,请及时绑定邮箱和手机立即绑定

如何使用类加载器加载 apach xmlbeans 类?

如何使用类加载器加载 apach xmlbeans 类?

SMILET 2021-11-17 10:46:31
我们有一个默认生成 pdf 输出的报告应用程序,但您可以编写自己的类来生成任何其他输出格式。这样我就使用 apache poi 10.0.0 生成了 xls 文件。但是,现在出现了生成 xlsx 文件的请求。当我尝试使用此代码创建工作簿时:XSSFWorkbook wbTemplate=new XSSFWorkbook()我收到错误:java.lang.NoSuchMethodError: org.apache.xmlbeans.XmlOptions.setSaveAggressiveNamespaces()Lorg/apache/xmlbeans/XmlOptions;我发现该应用程序已经使用了一个非常旧版本的 xmlbeans 文件,该文件当然不包含上述方法。首先,我尝试用更新的版本替换 xml bean 文件,以防万一,但应用程序冻结了。我的下一个想法是使用 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 下运行预先感谢您的回答。
查看完整描述

1 回答

?
蝴蝶不菲

TA贡献1810条经验 获得超4个赞

URLClassLoader(java.net.URL[])指出:

使用默认委托父 ClassLoader为指定的 URL 构造一个新的 URLClassLoader 。

因此,默认委托父类加载器也将被使用,因此org.apache.xmlbeans.XmlOptions如果找到,将从那里加载,而不是从附加的给定URL.

因此,我们需要使用默认的代理父类加载器。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. 那是因为这些 jar 位于默认父类加载器的类路径中。


然后第二个代码部分将默认父类加载器设置为 null,因此仅使用此类加载器加载类。


但是搞乱类加载器是一团糟。正如我的代码所暗示的,将默认父类加载器设置为 null,我们需要为当前类加载器提供所有需要的类源。这通常变得非常昂贵。因此,在类路径中没有旧的jars 总是比乱用类加载器更好的解决方案。


查看完整回答
反对 回复 2021-11-17
  • 1 回答
  • 0 关注
  • 116 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信