Powermock imageio UnsatisfiedLinkError

easymock, java, javax.imageio, powermock

Solution

The solution is to tell PowerMock to ignore all JRE classes which conflict with its custom class loader. That is, add the following annotation to the test class:

@PowerMockIgnore({"javax.imageio.*", "javax.security.*"})

(Note the `value` attribute of the annotation takes an array of regular expressions; it does not support multiple comma-separated expressions in a single string.)

The explanation for why this is needed is that

- PowerMock operates by re-loading the prepared class (and also the test class) in its own custom classloader;

- when `App` calls into `javax.imageio.ImageIO`, it ends up trying to load & initialize the internal class `com.sun.imageio.plugins.jpeg.JPEGImageReader`, which then attempts to load some other `com.sun.imageio` classes from the caller class loader; and

- the class load fails because PowerMock's custom class loader apparently can't find those JRE classes (it's hard to tell exactly what happens at this point, because the loading is done by a native method in the `JPEGImageReader` class - maybe it attempts to load some native library as well).

Problem

After adding powermock (1.5.6 in combination with Easymock 3.2) to my current project (jdk 1.6.0) I get some test failures in test methods which worked perfectly fine before: java.lang.UnsatisfiedLinkError: com.sun.imageio.plugins.jpeg.JPEGImageReader.initReaderIDs(Ljava/lang/Class;Ljava/lang/Class;Ljava/lang/Class;)V The following code fails: ``` BufferedImage img = null; try { img = ImageIO.read(this.getClass().getResourceAsStream("/example.jpg")); } catch (IOException e) { fail(e.getMessage()); } ``` The powermock page already has a bug from 2009 but no fix and no workaround. (Going back to 32Bit is nonsense since those methods work without powermock) So does anybody know how to fix this? Update I: A switch to 32 Bit is no option and besides that this is not the problem. If I don't use PowerMock every test is working perfectly in my 64Bit JVM... Update II: Ok here are the requested infos Update III: Extended the class Class to be tested ``` import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.cert.X509Certificate; import javax.imageio.ImageIO; import sun.security.x509.CertificateIssuerName; import sun.security.x509.CertificateSubjectName; import sun.security.x509.X500Name; import sun.security.x509.X509CertImpl; import sun.security.x509.X509CertInfo; public class App { private X509Certificate certificate = null; public ByteArrayOutputStream readImage() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); BufferedImage img = null; try { img = ImageIO.read(this.getClass().getResourceAsStream("/example.jpg")); ImageIO.write(img, "png", baos); } catch (IOException e) { e.printStackTrace(); } return baos; } public String readCertificate() throws Exception{ this.certificate = generateCertificate(); return this.certificate.getIssuerX500Principal().getName(); } private static X509Certificate generateCertificate() throws GeneralSecurityException, IOException{ X509CertInfo info = new X509CertInfo(); X500Name owner = new X500Name("CN=example.net"); info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner)); info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner)); return new X509CertImpl(info); } } ``` Test case: ``` import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PowerMockIgnore; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest(App.class) @PowerMockIgnore("javax.imageio.*, javax.security.*") public class AppTest { @Test public void testApp(){ App test = new App(); Assert.assertNotNull(test.readImage()); Assert.assertEquals(284506, test.readImage().size()); } @Test public void testCertificate() throws Exception{ App test = new App(); test.readCertificate(); } } ``` Maven dependencies: ``` <dependencies> <!-- TEST --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>1.5.6</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-easymock</artifactId> <version>1.5.6</version> <scope>test</scope> </dependency> ``` So if you comment the line: `//@RunWith(PowerMockRunner.class)` it is working. If uncommented it the above error is thrown (again!)

Original source

Related problems