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!)
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
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 JPEGImageReader class - maybe it attempts to load some native library as well).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With