Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAI vendorname == null

Tags:

java

jai

So I finished coding my application to rotate TIFF images which required JAI to manipulate the TIFFs.

It works fine when working under Eclipse, but whenever I build a fat jar for the library and then create one implementing that (per http://fjep.sourceforge.net/fjeptutorial.html), when I do the java -jar Push.jar \path\to\dir, it runs up until it hits the part where it is compressing and saving:

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.");

It blows up on the first line of that section with the message:

 Exception in thread "main" java.lang.IllegalArgumentException: vendorName == null!
 ....rest of stack trace.
like image 774
Robert Avatar asked Aug 13 '11 16:08

Robert


5 Answers

Since I spent a considerable amount of time debugging this problem, I thought I would share my solution here, despite the age of the question. Srikanth's second link was particularly helpful.

Reason for the error

JAI requires a vendor name for some of its deep internals, particularly the javax.imageio.spi.IIOServiceProvider which gets used by many (all?) of the image readers for their low-level IO. It's not picky what the string is, but it can't be null.

Rather than hard-code the vendor name, the ImageReaderSpi class gets the vendor name from sun.media.imageioimpl.common.PackageUtil.getVendor(). This in turn reads it from the jar's MANIFEST.MF. Normally you link against the standard jai-imageio packagage, so Sun's vendor info gets read. However, since you're making a fat jar file, you replaced Sun's MANIFEST.MF with your own which lacks the required information.

Solution

Include the following lines in your MANIFEST.MF file:

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.

The values for each property can be anything (I used my specific application/version/company), as long as all six are defined.

Maven

If you were using maven's assembly plugin to create your fat jar, maven can automatically include the correct version numbers and such. Update your pom.xml with the following <archive> section:

<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>
like image 198
Quantum7 Avatar answered Nov 15 '22 23:11

Quantum7


The accepted answer by Quantum7 explains the source of the problem, and in the Maven section it provides a solution when using the Maven Assembly plugin to produce a JAR including dependencies. If you are instead using the Maven Shade plugin to produce the JAR with dependencies, the configuration is slightly different. You can add something like the following to the configuration section of the Shade plugin in your 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>
like image 40
abyrd Avatar answered Nov 16 '22 00:11

abyrd


I had to use this ImageIO jar. It worked like a charm. Found it here.

like image 30
ScratchMyTail Avatar answered Nov 16 '22 00:11

ScratchMyTail


DISCLAIMER

The issue that I was having was slightly different, I was getting the "ClassNotFound" error while trying to run a compiled jar file. I happened upon this SO question while researching, so for others who followed the same trail that I did, here you go.

Possible Solution to ClassNotFound Error

To those who may find this question later on, if nothing else seems to work, You could try using the Apache Shader plugin for Maven. Here is some more information on it.

I'm not experienced enough to be able to tell you how it does it, but Apache Shader packages all the used dependencies in your project into the final jar file, so that all the dependencies are included in the META-INF folder when it's built. This increases the size of the jar file (depending on how many libraries you used in your project), but also seems to fix the jar not being able to find classes from outside libraries that are used.

To use the Shader plugin, add the following to your POM. I included it after the dependencies tag and before the properties tag.

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

NOTE: Make sure you change the package and class name to reflect your project's package and class names.

Other useful links: Similar stack overflow question

like image 2
Scrambo Avatar answered Nov 16 '22 01:11

Scrambo


(Would have been a comment on Quantum7's answer if I had enough reputation)

I ran into the same problem. Quantum7's answer saved the day! After putting in manifestEntries Specification-Vendor and Implementation-Vendor, however, the execution of my fat jar still failed with the exception below. Note it is

version == null!

not

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

Putting in manifestEntries below fixed it.

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

When running the fat jar, I made sure that none of the three values in the code below is 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());
    }
}
like image 2
Big Pumpkin Avatar answered Nov 16 '22 01:11

Big Pumpkin