【问题标题】:JAI vendorname == nullJAI 供应商名称 == null
【发布时间】:2011-10-26 11:13:03
【问题描述】:

所以我完成了我的应用程序的编码以旋转 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.

【问题讨论】:

    标签: java jai


    【解决方案1】:

    由于我花了相当多的时间来调试这个问题,我想我会在这里分享我的解决方案,尽管这个问题已经很久了。 Srikanth 的第二个link 特别有帮助。

    错误原因

    JAI 的一些深层内部结构需要供应商名称,尤其是 javax.imageio.spi.IIOServiceProvider,许多(全部?)图像阅读器都将其用于低级 IO。字符串是什么并不挑剔,但不能为空。

    ImageReaderSpi 类不是硬编码供应商名称,而是从 sun.media.imageioimpl.common.PackageUtil.getVendor() 获取供应商名称。这反过来 从 jar 的 MANIFEST.MF 中读取它。通常你链接到标准的 jai-imageio 包,所以 Sun 的供应商信息会被读取。但是,由于您正在制作一个胖 jar 文件,因此您将 Sun 的 MANIFEST.MF 替换为您自己的,但缺少所需的信息。

    解决方案

    在您的 MANIFEST.MF 文件中包含以下行:

    规范-标题:Java Advanced Imaging Image I/O Tools 规格版本:1.1 规格供应商:Sun Microsystems, Inc. 实施-标题:com.sun.media.imageio 实施版本:1.1 实施供应商:Sun Microsystems, Inc.

    每个属性的值可以是任何值(我使用了我的特定应用程序/版本/公司),只要定义了所有六个。

    Maven

    如果您使用 maven 的组装插件来创建您的 fat jar,maven 可以自动包含正确的版本号等。使用以下 &lt;archive&gt; 部分更新您的 pom.xml

    <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>
    

    【讨论】:

    • 比“官方”接受的解决方案更好、更清晰!谢谢!
    • 也许,但直到“正式”接受一个可行的解决方案两年后,这个答案才出现。我打算将它切换到这个只是因为第二个链接,即提供此处所写的解决方案但没有解释的链接,似乎已将链接蚕食,因此它不像当时那样有用。
    • 也许你可以看看 github.com/geoHeil/jai-packaging-problem 这不是同一个问题,即我检查了 maifest 条目,但胖罐子里的东西是空的。
    【解决方案2】:

    我不得不使用这个ImageIO jar。它就像一个魅力。找到了here

    【讨论】:

    • 注意:这个 imageio jar 已被修补以使用硬编码字符串来避免调用 PackageUtil 尝试从清单中解析 vendorName。
    【解决方案3】:

    Quantum7 接受的答案解释了问题的根源,并在 Maven 部分中提供了使用 Maven Assembly 插件生成包含依赖项的 JAR 时的解决方案。如果您改为使用 Maven Shade 插件来生成具有依赖项的 JAR,则配置会略有不同。您可以在 pom.xml 中的 Shade 插件的配置部分添加如下内容:

    <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>
    

    【讨论】:

      【解决方案4】:

      免责声明

      我遇到的问题略有不同,我在尝试运行已编译的 jar 文件时收到“ClassNotFound”错误。我在研究时偶然发现了这个 SO 问题,所以对于那些和我一样追随的其他人,你去吧。

      ClassNotFound 错误的可能解决方案

      对于那些以后可能会发现这个问题的人,如果似乎没有其他工作,您可以尝试使用 Maven 的 Apache Shader 插件。 Here 是关于它的更多信息。

      我经验不够,无法告诉你是怎么做的,但是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>
      

      注意:确保更改包和类名以反映项目的包和类名。

      其他有用的链接:Similar stack overflow question

      【讨论】:

        【解决方案5】:

        (如果我有足够的声誉,本来会是对 Quantum7 的回答的评论)

        我遇到了同样的问题。 Quantum7 的回答拯救了这一天!然而,在放入 manifestEntries Specification-Vendor 和 Implementation-Vendor 之后,我的 fat jar 的执行仍然失败,但出现以下异常。注意是

        版本 == 空!

        不是

        vendorName == null!

        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>
        

        在运行fat jar时,我确保下面代码中的三个值都不为null。

        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());
            }
        }
        

        【讨论】:

        • 我的 maven 配置的“addDefaultImplementationEntries”部分根据项目属性定义标题和版本。如果您想将它们设置为 Sun 的信息(我不建议这样做;自定义条目可以正常工作),那么您应该省略 块。
        【解决方案6】:

        这些可以帮助您解决问题。

        How to run jai-imageio with source code

        vendorName == null

        【讨论】:

        • 底部链接有效。我删除了生成的清单的两个非主类部分,并将 JAI 规范的内容放在顶部。在执行 java -jar 之后加载正常。
        • 对于其他人:这基本上是this other answer中更好描述的事情
        • 我已将另一个答案设置为答案,因为解决问题的 vendorName == null 链接重定向到网站的社区部分,并且搜索该字符串只会返回一个类似的问题问题。
        【解决方案7】:

        在为许多解决方案而苦苦挣扎后,我也遇到了同样的错误,并为我工作。

        需要在代码中手动给出供应商名称:

        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 中运行良好,但在导出的可运行 jar 中出现异常。

        写完上面的代码并导出jar,终于成功了。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-10-28
          • 1970-01-01
          • 2015-04-07
          • 1970-01-01
          • 2021-08-03
          • 2018-03-20
          • 1970-01-01
          相关资源
          最近更新 更多