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: расширен класс
-
Класс должен быть проверено
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); } }
-
Тестовый случай:
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> <!-- 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 ответ:
Решение состоит в том, чтобы сказать PowerMock игнорировать все классы JRE, которые конфликтуют с его пользовательским загрузчиком классов. То есть добавьте в тестовый класс следующую аннотацию:
@PowerMockIgnore({"javax.imageio.*", "javax.security.*"})
(обратите внимание, что атрибут
value
аннотации принимает массиврегулярных выражений ; он не поддерживает несколько разделенных запятыми выражений в одной строке.)Объяснение, почему это необходимо, состоит в том, что
- PowerMock работает путем повторной загрузки подготовленного класса (и также тестовый класс) в собственном пользовательском загрузчике классов;
- Когда
App
вызываетjavax.imageio.ImageIO
, он в конечном итоге пытается загрузить и инициализировать внутренний классcom.sun.imageio.plugins.jpeg.JPEGImageReader
, который затем пытается загрузить некоторые другиеcom.sun.imageio
классы из вызывающего загрузчика классов; и- загрузка класса завершается неудачей, потому что пользовательский загрузчик классов PowerMock, по-видимому, не может найти эти классы JRE (трудно точно сказать, что происходит в этот момент, потому что загрузка выполняется собственным методом в классе
JPEGImageReader
- возможно, он также пытается загрузить какую-то родную библиотеку).