I'm working with ImageIO and I'm trying to package the code into a JAR, however, I found out (after some debugging) that the PSD plugin is not present inside of the packaged JAR
I found out thanks to the code in this answer: Add/remove ImageReader from jar to ImageIO-registry
In my pom.xml I have the following ImageIO dependencies:
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-bmp</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-psd</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-core</artifactId>
<version>3.4</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-metadata</artifactId>
<version>3.4</version>
</dependency>
The maven command I use is:
clean compile assembly:single
Side note the code I used to debug:
ImageIO.scanForPlugins()
IIORegistry.getDefaultInstance().registerApplicationClasspathSpis()
val ir = ImageIO.getImageReadersByFormatName("PSD")
while (ir.hasNext())
{
val r = ir.next() as ImageReader
println(r)
}
Which in IDE prints:
com.twelvemonkeys.imageio.plugins.psd.PSDImageReader@1963006a
And when running the jar from a commandline it doesn't print anything, leading me to believe the PSD plugin is not working inside of the JAR but how?
The problem is that the target assembly:single
merges "everything" from your own project and all referenced JARs into one JAR but skips files that exist there yet.
ImageIO relies on the SPI/service loader mechanism of Java and therefore the plugins will be loaded via META-INF\services\javax.imageio.spi.ImageReaderSpi
. However, when having more than one JAR with such a file and using assembly:single
, one of those file "wins" and the ones from the other JARs are skipped. In your project, both imageio-bmp
and imageio-psd
do have such a file and the first one "wins" in the resulting JAR. (Seems like the IDE loads those files in another order and the correct version "wins", but that is just a guess.)
Solution: Maven should merge all META-INF\services\javax.imageio.spi.ImageReaderSpi
files into one file in the resulting JAR. To do that, Maven needs additional configuration information.
descriptor.xml
to the root of your project, something like this:<?xml version="1.0" encoding="UTF-8"?>
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<!-- copied from jar-with-dependencies (http://maven.apache.org/plugins/maven-assembly-plugin/descriptor-refs.html#jar-with-dependencies) -->
<id>jar-with-deps-merge-services</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>metaInf-services</handlerName>
</containerDescriptorHandler>
</containerDescriptorHandlers>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
The important part is the metaInf-services
setting which merges the files in META-INF\services
.
descriptor.xml
in your pom.xml
:[...]
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<archive>
<manifest>
<mainClass>your.main.MainClass</mainClass>
</manifest>
</archive>
<descriptors>
<descriptor>descriptor.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
Important notes:
jar-with-dependencies
in your build config, this should be removed there because the descriptor file includes that setting.Even though I tried this on a sample project, this solution might not be perfect and you might adapt it according to your needs, but I hope this is a suitable point to start from.