「テストをEclipse上で実行してOKが出たら、カバレッジを取るためにMavenでテストを実行」てな感じで作業を進めてるのですが、Maven実行時に下記のような例外が発生することがあります。
なお、環境は次の通りです。
解決策としては、テストクラスに次のアノテーションを追加すると良いそうです。
java.lang.UnsatisfiedLinkError: Native Library C:\Java\jdk1.8.0_144_x64\jre\bin\jpeg.dll already loaded in another classloader
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1907)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1845)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter$1.run(JPEGImageWriter.java:180)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter$1.run(JPEGImageWriter.java:178)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.(JPEGImageWriter.java:177)
at com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi.createWriterInstance(JPEGImageWriterSpi.java:96)
at javax.imageio.spi.ImageWriterSpi.createWriterInstance(ImageWriterSpi.java:351)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:843)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:827)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1596)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
...
試している限りでは次のような条件で発生するようです。
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1907)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1845)
at java.lang.Runtime.loadLibrary0(Runtime.java:870)
at java.lang.System.loadLibrary(System.java:1122)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter$1.run(JPEGImageWriter.java:180)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter$1.run(JPEGImageWriter.java:178)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.imageio.plugins.jpeg.JPEGImageWriter.
at com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi.createWriterInstance(JPEGImageWriterSpi.java:96)
at javax.imageio.spi.ImageWriterSpi.createWriterInstance(ImageWriterSpi.java:351)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:843)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:827)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1596)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
...
- 複数のテストクラスでImageIOを利用するクラスが呼ばれる
- テスト開始後、2つ目のテストクラス実行時に上記例外が発生する
java.lang.NoClassDefFoundError: Could not initialize class com.sun.imageio.plugins.jpeg.JPEGImageWriter
at com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi.createWriterInstance(JPEGImageWriterSpi.java:96)
at javax.imageio.spi.ImageWriterSpi.createWriterInstance(ImageWriterSpi.java:351)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:843)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:827)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1596)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
...
目的のクラスが読み込まれてないので、NoClassDefFoundErrorが発生するのも当然ですね。at com.sun.imageio.plugins.jpeg.JPEGImageWriterSpi.createWriterInstance(JPEGImageWriterSpi.java:96)
at javax.imageio.spi.ImageWriterSpi.createWriterInstance(ImageWriterSpi.java:351)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:843)
at javax.imageio.ImageIO$ImageWriterIterator.next(ImageIO.java:827)
at javax.imageio.ImageIO.getWriter(ImageIO.java:1596)
at javax.imageio.ImageIO.write(ImageIO.java:1520)
...
なお、環境は次の通りです。
- Java SE Development Kit 8u144 (ImageIOを含む)
- Apache Maven 3.5.0
- PowerMock 1.7.3
原因はPowerMockのクラスローダー
調べたところ、事象はちょっと違うのですが、次の記事が見つかりました。- stackoverflow
- Powermock imageio UnsatisfiedLinkError
@PowerMockIgnore({"javax.imageio.*", "javax.security.*"})
発生する原因は次のような理由みたいです。
- PowerMockを利用するクラスでは、デフォルトのクラスローダーではなくPowerMockが用意するクラスローダーが使われる。
- ImageIOはImageIOが持つクラスローダーで別のクラスをロードする。
- 2つ目のテストクラス実行時、再度PowerMockによりImageIOが読み込まれるが、その際にImageIOのクラスローダーが再度別クラスを読み込みに行ってしまう。
- この現象はPowerMockを利用したテストクラスでのみ起こるため、それであればPowerMockのクラスローダーでImageIO関連のクラスを読み込まなければ良い。
JAI ImageIOを利用している場合
Tiff形式などImageIOがサポートしていない形式を扱う場合、JAI ImageIOを利用するかと思います。- jai-imageio-core 1.3.1
java.lang.LinkageError: loader constraint violation: when resolving overridden method "com.github.jaiimageio.impl.plugins.tiff.TIFFStreamMetadata.mergeTree(Ljava/lang/String;Lorg/w3c/dom/Node;)V" the class loader (instance of org/powermock/core/classloader/MockClassLoader) of the current class, com/github/jaiimageio/impl/plugins/tiff/TIFFStreamMetadata, and its superclass loader (instance of ), have different Class objects for the type org/w3c/dom/Node used in the signature
at com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriter.getDefaultStreamMetadata(TIFFImageWriter.java:336)
at com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriter.write(TIFFImageWriter.java:2522)
at com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriter.write(TIFFImageWriter.java:2383)
at javax.imageio.ImageWriter.write(ImageWriter.java:615)
at javax.imageio.ImageIO.doWrite(ImageIO.java:1612)
at javax.imageio.ImageIO.write(ImageIO.java:1536)
...
これもPowerMockのクラスローダーが原因のようなので、@PowerMockIgnoreに次のクラスを追加してください。
at com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriter.getDefaultStreamMetadata(TIFFImageWriter.java:336)
at com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriter.write(TIFFImageWriter.java:2522)
at com.github.jaiimageio.impl.plugins.tiff.TIFFImageWriter.write(TIFFImageWriter.java:2383)
at javax.imageio.ImageWriter.write(ImageWriter.java:615)
at javax.imageio.ImageIO.doWrite(ImageIO.java:1612)
at javax.imageio.ImageIO.write(ImageIO.java:1536)
...
com.github.jaiimageio.*
これでLinkageErrorも解消します。
コメント