私たちは、デフォルトでは、PDF出力を生成することを報告aplicationを持っていますが、他の出力形式を生成するために、独自のクラスを書くことができます。この方法で私は、Apache POI 10.0を使用してXLSファイルを生成しています。しかし、今のxlsxファイルを生成するための要求が来ました。私はこのコードでブックを作成しようとすると:
XSSFWorkbook wbTemplate=new XSSFWorkbook()
私はエラーを得ました:
java.lang.NoSuchMethodError: org.apache.xmlbeans.XmlOptions.setSaveAggressiveNamespaces()Lorg/apache/xmlbeans/XmlOptions;
私は、アプリケーションがすでにもちろん、上記の方法が含まれていないことをXMLBeansのファイルの非常に古いバージョンを使用していることを発見しました。まず、私はちょうど私が運を持っている場合には、より新しいバージョンを持つXML Beanファイルを置き換えるためにしようと試みたが、アプリケーションがフリーズします。
私の次のアイデアは、クラスローダを使用して、アプリが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」メソッド名を取得したいです。それから私は、ファイルにこのクラスのすべての関数名を書かれているし、それが真である、その名前は存在しません。しかし、1つのSで「setSaveAggresiveNamespaces」と呼ばれる別のものを存在します!私はXSSFを作成するためにwan'tとき、私それが動作します。この呼び出すと、もちろん、私はまだ(ダブルSS付き)setSaveAggressiveNamespacesが存在しないというメッセージが表示されますワークブック。しかしsetSaveAggressiveNamespacesが、これはApacheのポイパッケージに来ているので、クラスにする必要があります。
私はそれを動作させるために、この場合に何ができますか?アプリケーションは、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ファイル:ファイル:/ C:!/ HOME /インストールします/ ApacheのPOI / POI-3.10 / OOXML-libに/ XMLBeansの-2.3.0.jar / ORG / apacheの/ XMLBeansの/ RESOURCEは、次のようにログに書かれていますXmlOptions.class」
URLClassLoaderの(のjava.net.URL [])状態:
指定されたURLの新しいURLClassLoaderを構築し、デフォルトの委譲の親である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
。これらのjarファイルは、デフォルトの親クラスローダのクラスパス内にあるためです。
2番目のコード部分は、デフォルトの親クラスローダはnullを設定し、そのクラスは、このクラスローダを使用してロードされます。
しかし、クラスローダをいじりは混乱です。デフォルトの親クラスローダセットヌルを持つ、私のコードで示唆されるように、我々は必要なすべてのクラスのソースローダー現在のクラスを与える必要があります。これは、多くの場合、非常に高価なものとなります。そうでない古い持つjar
クラスパスにSは常にクラスローダをいじりよりも優れたソリューションとなります。