Powermock imageio UnsatisfiedLinkError


После добавления powermock (1.5.6 в сочетании с Easymock 3.2) в мой текущий проект (jdk 1.6.0) я получаю некоторые провалы в тестовых методах, которые прекрасно работали раньше:

[5]}Java.яз..UnsatisfiedLinkError: ком.солнце.imageio.подключаемый модуль.формате 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());
}

На странице powermock уже есть ошибка от 2009 года, но нет исправления и нет обход. (Возвращение к 32 битам-это нонсенс, поскольку эти методы работают без powermock) так кто-нибудь знает, как это исправить?

Update I: переключение на 32-бит не является вариантом, и, кроме того, это не проблема. Если я не использую PowerMock, каждый тест отлично работает в моем 64-битном JVM...

Обновление II: Ok вот запрошенная информация

Обновление 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);
     }   
    }
    
  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();
     }
    }
    
  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>
    

Итак, если вы прокомментируете строку: //@RunWith(PowerMockRunner.class) это работает. Если он раскомментирован, то вышеприведенная ошибка выбрасывается (опять!)

1 2

1 ответ:

Решение состоит в том, чтобы сказать PowerMock игнорировать все классы JRE, которые конфликтуют с его пользовательским загрузчиком классов. То есть добавьте в тестовый класс следующую аннотацию:

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

(обратите внимание, что атрибут value аннотации принимает массиврегулярных выражений ; он не поддерживает несколько разделенных запятыми выражений в одной строке.)

Объяснение, почему это необходимо, состоит в том, что

  1. PowerMock работает путем повторной загрузки подготовленного класса (и также тестовый класс) в собственном пользовательском загрузчике классов;
  2. Когда App вызывает javax.imageio.ImageIO, он в конечном итоге пытается загрузить и инициализировать внутренний класс com.sun.imageio.plugins.jpeg.JPEGImageReader, который затем пытается загрузить некоторые другие com.sun.imageio классы из вызывающего загрузчика классов; и
  3. загрузка класса завершается неудачей, потому что пользовательский загрузчик классов PowerMock, по-видимому, не может найти эти классы JRE (трудно точно сказать, что происходит в этот момент, потому что загрузка выполняется собственным методом в классе JPEGImageReader - возможно, он также пытается загрузить какую-то родную библиотеку).