Powermock imageio UnsatisfiedLinkError

Lon*_*zak 2 java easymock powermock javax.imageio

在我的当前项目(jdk 1.6.0)中添加了powermock(1.5.6与Easymock 3.2的组合)之后,我在测试方法中遇到了一些测试失败,这些测试方法之前完全正常:

java.lang.UnsatisfiedLinkError:com.sun.imageio.plugins.jpeg.JPEGImageReader.initReaderIDs(Ljava/lang/Class; Ljava/lang/Class; Ljava/lang/Class;)V

以下代码失败:

BufferedImage img = null;
try {
    img = ImageIO.read(this.getClass().getResourceAsStream("/example.jpg"));
}
catch (IOException e) {
    fail(e.getMessage());
}
Run Code Online (Sandbox Code Playgroud)

powermock页面已经有一个2009年的错误,但没有修复,没有解决方法.(回到32Bit是无稽之谈,因为这些方法没有电动摇摆工作)所以有人知道如何解决这个问题吗?

更新I:切换到32位是没有选择,除此之外,这不是问题.如果我不使用PowerMock,每个测试都在64Bit JVM中完美运行......

更新II:这里是请求的信息

更新III:扩展课程

  1. 要测试的类

    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);
     }   
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 测试用例:

    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();
     }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. Maven依赖:

    <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>
    
    Run Code Online (Sandbox Code Playgroud)

所以,如果你评论这条线: //@RunWith(PowerMockRunner.class) 它是有效的.如果取消注释,则抛出上述错误(再次!)

Rog*_*rio 10

解决方案是告诉PowerMock忽略与其自定义类加载器冲突的所有JRE类.也就是说,将以下注释添加到测试类:

@PowerMockIgnore({"javax.imageio.*", "javax.security.*"})
Run Code Online (Sandbox Code Playgroud)

(注意,注释的value属性采用正则表达式数组 ;它不支持单个字符串中的多个逗号分隔表达式.)

需要解释为什么需要这样做

  1. PowerMock通过在自己的自定义类加载器中重新加载准备好的类(以及测试类)来运行;
  2. App调用时javax.imageio.ImageIO,它最终尝试加载并初始化内部类com.sun.imageio.plugins.jpeg.JPEGImageReader,然后内部类尝试com.sun.imageio调用者类加载器加载一些其他类; 和
  3. 类加载失败,因为PowerMock的自定义类加载器显然无法找到那些JRE类(很难确切地说明此时发生了什么,因为加载是由类中的本机方法完成的JPEGImageReader- 可能它尝试加载一些本机库以及).