Search code examples
mavenjarapache-felixmaven-shade-plugin

How to use maven-shade and felix to generate a shaded jar with a new manifest


I'm currently working on a project that is attempting to integrate use both shade and felix. The goal is to create a shaded jar that contains only the code we need, then use felix to create the manifest we need. The build part of my pom is as follows:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.3</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <shadedArtifactAttached>false</shadedArtifactAttached>
                        <artifactSet>
                            <includes>
                                <include>${project.groupId}:*</include>
                            </includes>
                        </artifactSet>
                        <transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
                        </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

        <plugin>
            <groupId>org.apache.felix</groupId>
            <artifactId>maven-bundle-plugin</artifactId>
            <executions>
                <execution>
                    <id>bundle-manifest</id>
                    <phase>package</phase>
                    <goals>
                        <goal>manifest</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <manifestLocation>${project.build.directory}</manifestLocation>
                <niceManifest>true</niceManifest>
            </configuration>
        </plugin>

    </plugins>
</build>

Now the issue I'm running in to is something I've seen elsewhere, but all of those threads seem to die right at this point. So the shaded jar is correctly created, then Felix runs afterwards and puts the MANIFEST.MF file (which is correct as far as I can tell) in target/classes/META-INF/ but it doesn't put that same manifest in the shaded jar. The one inside the jar is the same manifest that existed before Felix ran.

It almost seems like I need Shade to run, then Felix, then re-run the jar creation. Am I missing something?

I'm trying to figure out how to, for lack of a better term, re-package the JAR with the new manifest.


Solution

  • Your main problem is that the manifest must be generated in the jar file, you can generate your Manifest file from the shade plugin (adapt with your needs):

     <configuration>
            <transformers>
                <!-- This bit sets the main class for the executable jar as you otherwise -->
                <!-- would with the assembly plugin -->
                <transformer
                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                    <manifestEntries>
                        <Import-Package>org.apache.common</Import-Package>
                        <Export-Package>org.test</Export-Package>
                        <Main-Class>com.br.iacit.tutorialdoJar.ImageLab</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>
                    </manifestEntries>
                </transformer>
                <!-- This bit merges the various GeoTools META-INF/services files -->
                <transformer
                    implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
            </transformers>
        </configuration>
    

    Output Manifest:

    Manifest-Version: 1.0
    Toto: test
    Export-Package: org.test
    Archiver-Version: Plexus Archiver
    Built-By: NG673AB
    X-Compile-Target-JDK: 1.7
    Import-Package: org.apache.common
    X-Compile-Source-JDK: 1.7
    Created-By: Apache Maven 3.3.3
    Build-Jdk: 1.8.0_66
    Main-Class: tt.tt.main
    

    Edit: I managed to make it so that it compiles correctly, see below:

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>1.3</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
                                    <resource>META-INF/MANIFEST.MF</resource>
                                </transformer>
                                <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.IncludeResourceTransformer">
                                    <resource>META-INF/MANIFEST.MF</resource>
                                    <file>src/main/resources/MANIFEST.MF</file>
                                </transformer>
                            </transformers>
                            <shadedArtifactAttached>false</shadedArtifactAttached>
                            <artifactSet>
                                <includes>
                                    <include>${project.groupId}:*</include>
                                </includes>
                            </artifactSet>
    
                        </configuration>
                    </execution>
                </executions>
            </plugin>
    
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <executions>
                    <execution>
                        <id>bundle-manifest</id>
                        <phase>package</phase>
                        <goals>
                            <goal>manifest</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <manifestLocation>src/main/resources/</manifestLocation>
                    <niceManifest>true</niceManifest>
                    <instructions>
                        <Export-Package>test</Export-Package>
                    </instructions>
                </configuration>
            </plugin>
    
        </plugins>
    </build>