Имя поставщика JAI == ноль

Итак, я закончил кодировать свое приложение для поворота изображений TIFF, для чего требовался JAI для управления TIFF.

Он отлично работает при работе в Eclipse, но всякий раз, когда я создаю толстый jar-файл для библиотеки, а затем создаю его реализацию (согласно http://fjep.sourceforge.net/fjeptutorial.html), когда я делаю java -jar Push.jar \path\to\dir, он работает до тех пор, пока не достигнет той части, где он сжимается и сохранение:

TIFFImageWriterSpi tiffspi = new TIFFImageWriterSpi();
ImageWriter writer = tiffspi.createWriterInstance();
//Iterator<ImageWriter> iter =  ImageIO.getImageWritersByFormatName("TIFF");
//ImageWriter writer = iter.next();

ImageWriteParam param2 = writer.getDefaultWriteParam();
param2.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);

param2.setCompressionType("LZW");
param2.setCompressionQuality(0.0f);
File fOutputFile = workArea[i];
ImageOutputStream ios = ImageIO.createImageOutputStream(fOutputFile);
writer.setOutput(ios);

if (frontPage == 1)
{
     writer.write(null, new IIOImage(pg1, null, null), param2);
     writer.writeInsert(-1, new IIOImage(pg2, null, null), param2);
}
else if (frontPage == 2)
{
     writer.write(null, new IIOImage(pg2, null, null), param2);
     writer.writeInsert(-1, new IIOImage(pg1, null, null), param2);
}

remaining = remaining - 1;
    if (remaining > 0)
     System.out.println(remaining + " remaining.");
else
     System.out.println("Done.");

Он взрывается на первой строке этого раздела с сообщением:

 Exception in thread "main" java.lang.IllegalArgumentException: vendorName == null!
 ....rest of stack trace.

person Robert    schedule 13.08.2011    source источник


Ответы (7)


Поскольку я потратил значительное количество времени на отладку этой проблемы, я решил поделиться здесь своим решением, несмотря на возраст вопроса. Вторая ссылка Шриканта оказалась особенно полезной.

Причина ошибки

JAI требует имя поставщика для некоторых своих глубоких внутренних компонентов, в частности javax.imageio.spi.IIOServiceProvider, который используется многими (всеми?) программами чтения изображений для их низкоуровневого ввода-вывода. Неважно, что это за строка, но она не может быть нулевой.

Вместо жесткого кодирования имени поставщика класс ImageReaderSpi получает имя поставщика из функции sun.media.imageioimpl.common.PackageUtil.getVendor(). Это, в свою очередь, считывает его из файла MANIFEST.MF jar. Обычно вы связываетесь со стандартным пакетом jai-imageio, поэтому информация о поставщике Sun считывается. Однако, поскольку вы создаете толстый jar-файл, вы заменили Sun MANIFEST.MF своим собственным, в котором отсутствует необходимая информация.

Решение

Включите следующие строки в файл MANIFEST.MF:

Specification-Title: Java Advanced Imaging Image I/O Tools
Specification-Version: 1.1
Specification-Vendor: Sun Microsystems, Inc.
Implementation-Title: com.sun.media.imageio
Implementation-Version: 1.1
Implementation-Vendor: Sun Microsystems, Inc.

Значения для каждого свойства могут быть любыми (я использовал свое конкретное приложение/версию/компанию), если определены все шесть.

Мавен

Если вы использовали плагин сборки maven для создания своей толстой банки, maven может автоматически включать правильные номера версий и тому подобное. Обновите свой pom.xml следующим разделом <archive>:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
        <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        <archive>
            <manifest>
                <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
            </manifest>
            <manifestEntries>
                <Specification-Vendor>MyCompany</Specification-Vendor>
                <Implementation-Vendor>MyCompany</Implementation-Vendor>
            </manifestEntries>
        </archive>
    </configuration>
    <executions>
        <execution>
            <id>create-my-bundle</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>
person Quantum7    schedule 28.08.2013
comment
Лучше и понятнее, чем официально принятое решение! Спасибо! - person Funkwecker; 24.08.2016
comment
Возможно, но этот ответ пришел только через 2 года после официального принятия рабочего решения. Я собираюсь переключить его на этот только потому, что вторая ссылка, та, которая предоставила решение, как написано здесь, но без объяснения, похоже, каннибализировала ссылку, поэтому она не так полезна, как это было в то время. - person Robert; 28.12.2016
comment
Может быть, вы можете взглянуть на github.com/geoHeil/jai-packaging-problem. это не та же проблема, т.е. я проверил самые важные записи, но что-то в толстой банке пусто. - person Georg Heiler; 03.06.2017

Мне пришлось использовать этот банк ImageIO. Оно работало завораживающе. Найдено здесь.

person ScratchMyTail    schedule 05.12.2011
comment
Примечание. Этот jar-файл imageio был исправлен, чтобы использовать жестко закодированные строки, чтобы избежать вызова PackageUtil, который пытается разрешить vendorName из манифеста. - person eis; 04.02.2015

Принятый ответ Quantum7 объясняет источник проблемы, а в разделе Maven он предоставляет решение при использовании плагина Maven Assembly для создания JAR, включая зависимости. Если вместо этого вы используете подключаемый модуль Maven Shade для создания JAR с зависимостями, конфигурация немного отличается. Вы можете добавить что-то вроде следующего в раздел конфигурации плагина Shade в вашем pom.xml:

<configuration>
    <transformers>
        <transformer
                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <manifestEntries>
                <Main-Class>com.conveyal.r5.R5Main</Main-Class>
                <Specification-Title>Java Advanced Imaging Image I/O Tools</Specification-Title>
                <Specification-Version>1.1</Specification-Version>
                <Specification-Vendor>Sun Microsystems, Inc.</Specification-Vendor>
                <Implementation-Title>com.sun.media.imageio</Implementation-Title>
                <Implementation-Version>1.1</Implementation-Version>
                <Implementation-Vendor>Sun Microsystems, Inc.</Implementation-Vendor>
                <Extension-Name>com.sun.media.imageio</Extension-Name>
            </manifestEntries>
        </transformer>
    </transformers>
</configuration>
person abyrd    schedule 04.01.2018

ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ

Проблема, с которой я столкнулся, была немного другой: я получал ошибку ClassNotFound при попытке запустить скомпилированный файл jar. Я столкнулся с этим ТАКИМ вопросом во время исследования, так что для тех, кто пошел по тому же пути, что и я, вот вам.

Возможное решение ошибки ClassNotFound

Для тех, кто может найти этот вопрос позже, если ничего не работает, вы можете попробовать использовать Apache Shader плагин для Maven. Вот дополнительная информация об этом.

У меня недостаточно опыта, чтобы рассказать вам, как это делается, но Apache Shader упаковывает все используемые зависимости в вашем проекте в окончательный файл jar, так что все зависимости включаются в Папка META-INF, когда она будет построена. Это увеличивает размер файла jar (в зависимости от того, сколько библиотек вы использовали в своем проекте), но также, похоже, исправляет то, что jar не может найти классы из внешних библиотек, которые используются.

Чтобы использовать подключаемый модуль Shader, добавьте следующее в свой файл POM. Я включил его после тега зависимостей и перед тегом свойств.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <filters>
                            <filter>
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <manifestEntries>
                                    <Main-Class>com.package.name.className</Main-Class>
                                    <Build-Number>1</Build-Number>
                                </manifestEntries>
                            </transformer>
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

ПРИМЕЧАНИЕ. Убедитесь, что вы изменили имя пакета и класса, чтобы они отражали имена пакетов и классов вашего проекта.

Другие полезные ссылки: Похожий вопрос о переполнении стека

person Scrambo    schedule 14.06.2016

(Был бы комментарий к ответу Quantum7, если бы у меня было достаточно репутации)

Я столкнулся с той же проблемой. Ответ Quantum7 спас положение! Однако после ввода манифестных спецификаций-вендора и реализации-вендора выполнение моей толстой банки все еще не удалось, за исключением ниже. Обратите внимание, что это

версия == ноль!

нет

vendorName == ноль!

java.util.ServiceConfigurationError: javax.imageio.spi.ImageReaderSpi: Provider com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReaderSpi could not be instantiated
        at java.util.ServiceLoader.fail(Unknown Source)
        at java.util.ServiceLoader.access$100(Unknown Source)
        at java.util.ServiceLoader$LazyIterator.nextService(Unknown Source)
        at java.util.ServiceLoader$LazyIterator.next(Unknown Source)
        at java.util.ServiceLoader$1.next(Unknown Source)
        at javax.imageio.spi.IIORegistry.registerApplicationClasspathSpis(Unknown Source)
        at javax.imageio.spi.IIORegistry.<init>(Unknown Source)
        at javax.imageio.spi.IIORegistry.getDefaultInstance(Unknown Source)
        at javax.imageio.ImageIO.<clinit>(Unknown Source)
        at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.IllegalArgumentException: version == null!
        at javax.imageio.spi.IIOServiceProvider.<init>(Unknown Source)
        at javax.imageio.spi.ImageReaderWriterSpi.<init>(Unknown Source)
        at javax.imageio.spi.ImageReaderSpi.<init>(Unknown Source)
        at com.sun.media.imageioimpl.plugins.jpeg.CLibJPEGImageReaderSpi.<init>(CLibJPEGImageReaderSpi.java:80)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at java.lang.Class.newInstance(Unknown Source)
        ... 14 more

Вставка в manifestEntries ниже исправила это.

<manifestEntries>
    <Specification-Title>Java Advanced Imaging Image I/O Tools</Specification-Title>
    <Specification-Version>1.1</Specification-Version>
    <Specification-Vendor>Sun Microsystems, Inc.</Specification-Vendor>
    <Implementation-Title>com.sun.media.imageio</Implementation-Title>
    <Implementation-Version>1.1</Implementation-Version>
    <Implementation-Vendor>Sun Microsystems, Inc.</Implementation-Vendor>
</manifestEntries>

При запуске толстой банки я убедился, что ни одно из трех значений в приведенном ниже коде не равно нулю.

import com.sun.media.imageioimpl.common.PackageUtil;

public class ManifestCheck {
    public static void main(String[] args) {
        System.out.println(PackageUtil.getVendor());
        System.out.println(PackageUtil.getVersion());
        System.out.println(PackageUtil.getSpecificationTitle());
    }
}
person Big Pumpkin    schedule 15.07.2016
comment
Часть «addDefaultImplementationEntries» моей конфигурации maven определяет заголовок и версию на основе свойств проекта. Если вы хотите установить для них информацию от Sun (что я не рекомендую; индивидуальные записи работают нормально), вам следует опустить блок ‹manifest›. - person Quantum7; 20.10.2016

Они могут помочь вам решить проблему.

Как запустить jai-imageio с исходным кодом

vendorName == null

person Srikanth Venkatesh    schedule 13.08.2011
comment
Нижняя ссылка работала. Я удалил два раздела сгенерированного манифеста, не относящиеся к основному классу, и поместил в него спецификацию JAI вверху. После этого загружается нормально при выполнении java -jar. - person Robert; 14.08.2011
comment
Для других: это, по сути, то, что лучше описано в этом другом ответе - person eis; 15.01.2015
comment
Я установил другой ответ как ответ, потому что ссылка vendorName == null, которая решила проблему, перенаправляется в раздел сообщества сайта, и поиск этой строки возвращает только вопрос с аналогичной проблемой. - person Robert; 28.12.2016

Я также получал ту же ошибку после того, как многие решения нашли это и сработали для меня.

Необходимо указать venderName вручную в коде как:

import com.sun.media.imageioimpl.common.PackageUtil;

    
    try {
        MainClass.afVenderNames(PackageUtil.class, "afreen", "afreen", "afreen");
    } catch (NoSuchFieldException e1) {
        e1.printStackTrace();
    } catch (SecurityException e1) {
        e1.printStackTrace();
    } catch (IllegalArgumentException e1) {
        e1.printStackTrace();
    } catch (IllegalAccessException e1) {
        e1.printStackTrace();
    }
    System.out.println(PackageUtil.getVendor());
    System.out.println(PackageUtil.getVersion());
    System.out.println(PackageUtil.getSpecificationTitle());
    
    
    
    public static void afVenderNames(Class<?> PackageUtil, String vendor, String version, String specTitle)
        throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
    Field vendorField = PackageUtil.getDeclaredField("vendor");
    vendorField.setAccessible(true);
    vendorField.set(null, vendor);

    Field versionField = PackageUtil.getDeclaredField("version");
    versionField.setAccessible(true);
    versionField.set(null, version);

    Field specTitleField = PackageUtil.getDeclaredField("specTitle");
    specTitleField.setAccessible(true);
    specTitleField.set(null, specTitle);
}

Неважно, каким будет значение vendorName, если оно не равно NULL. Мой код работал нормально в eclipse, но выдавал исключения в экспортированном исполняемом банке.

Наконец-то сработало, когда написал приведенный выше код и экспортировал банку.

person Afreen Shaikh    schedule 21.05.2021