Using maven-bundle-plugin with the maven-shade-plugin
Asked Answered
A

4

15

I'm using the maven-shade-plugin to relocate some packages during the package phase of my build. I'm also using the maven-bundle-plugin to generate a manifest. The problem is the bundle plugin runs before the shade plugin (during the process-classes phase), and doesn't include any of my shaded packages in the generated manifest's exports.

How can I get these two plugins to play nice with each other, so that my relocated packages are treated like any other package by the bundle plugin?

--

By request, the Shade and bundle sections of my POM:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
      <execution>
        <phase>package</phase>
        <goals>
          <goal>shade</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <filters>
        <filter>
          <artifact>cglib:cglib</artifact>
          <includes>
            <include>net/sf/cglib/core/**</include>
            <include>net/sf/cglib/proxy/**</include>
          </includes>
        </filter>
      </filters>
      <relocations>
        <relocation>
          <pattern>net.sf.cglib</pattern>
          <shadedPattern>org.modelmapper.internal.cglib</shadedPattern>
        </relocation>
        <relocation>
          <pattern>org.objectweb.asm</pattern>
          <shadedPattern>org.modelmapper.internal.asm</shadedPattern>
        </relocation>
      </relocations>
    </configuration>
  </plugin>

  <plugin>
    <groupId>org.apache.felix</groupId>
    <artifactId>maven-bundle-plugin</artifactId>
    <version>2.3.7</version>
    <executions>
      <execution>
        <id>bundle-manifest</id>
        <phase>process-classes</phase>
        <goals>
          <goal>manifest</goal>
        </goals>
      </execution>
    </executions>
    <configuration>
      <instructions>
        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
        <Export-Package>
          org.modelmapper,
          org.modelmapper.builder,
          org.modelmapper.config,
          org.modelmapper.convention,
          org.modelmapper.spi
        </Export-Package>
        <Private-Package>
          org.modelmapper.internal.**
        </Private-Package>
        <Import-Package>
          *
        </Import-Package>
        <Include-Resource>
          {maven-resources},
          {maven-dependencies}
        </Include-Resource>
      </instructions>
    </configuration>
  </plugin>

Taken from here

Adahadaha answered 16/8, 2013 at 19:19 Comment(10)
Please post the relevant parts of your pom.xml, including <Export-Package> and <relocations> sections.Serilda
Is this related to osgi and/or fuse ESB? worth adding those tags?Hippogriff
@Hippogriff - yes, OSGI. Which tags do you mean?Adahadaha
If you remove the executions binded to process-classes and package, then run mvn compile shade:shade bundle:manifest package from the command line, is the manifest generated correctly?Serilda
Also, are you using maven 3.0.3 or up?Serilda
@Adahadaha i meant to suggest adding the osgi tag to your question, which looks like has been done :)Hippogriff
@AnthonyAccioly Removing the executions from the plugins results in something like Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:2.1:shade (default-cli) on project modelmapper: Failed to create shaded artifact, project main artifact does not exist.... depending on what goals I execute. And yes, I'm using mvn 3.0.3.Adahadaha
Weird, what is your packaging type? JAR (<packaging>jar</packaging>) or Bundle? Try binding both plugins to package phase (making sure that maven bundle appears after maven shade in your plugin list). Does it package the bundle correctly and add the desired metadata?Serilda
Packaging is jar. Setting both plugins to run in package phase: Error assembling JAR: Manifest file: /Users/jonathan/dev/modelmapper/core/target/classes/META-INF/MANIFEST.MF does not exist. Full POMAdahadaha
It would be great if you could accept or post an answer to this question. It's been viewed over 4k times since 2013.Manicurist
S
7

Another option is to dump maven bundle plugin altogether and use Maven Shade Plugin ManifestResourceTransformer to add the desired OSGI metadata to the manifest.

Take a look at xbean-asm-shaded/pom.xml for a example.

<transformers>
  <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
    <manifestEntries>
      <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
      <Export-Package>
        org.apache.xbean.asm;org.modelmapper.builder; ...
      </Export-Package>
      <Import-Package>*</Import-Package>
      <Private-Package>org.modelmapper.internal ...</Private-Package>
   </manifestEntries>
</transformer>
Serilda answered 30/8, 2013 at 17:54 Comment(0)
N
2

Solution is very simple. You still can use maven-bundle-plugin and maven-shade-plugin at the same time. You just need to remember about the order. If you use bundle packaging maven bundle plugin will get executed during package phase before maven-shade. But that's not so wrong.

Here is the deal.

  • Use Private-Package: pkg.name.before.shading
  • Make maven-shade-plugin with one <include>null:null</include> - this will prevent shade plugin from creating empty jar
  • use maven-shade-plugin relocations - from pkg.name.before.shading to other.pkg.

You may see this trick working in FasterXML jackson-module-paranamer

Negrete answered 3/9, 2013 at 21:0 Comment(1)
This works perfectly except when you want to export the shaded packages themselves. The solution proposed here will only include packages from src/main/java.Decentralize
H
0

I assume that after the compile phase is done you want to:

  1. relocate some classes with the shade plugin
  2. create a manifest with the bundle plugin
  3. pack it all up with the jar plugin

The problem is the bundle plugin runs before the shade plugin

The bundle plugin is binded to process-classes phase which comes before the package phase to which the shade plugin is bound.

I suggest that you bind the shade plugin to process-classes phase also. Change shade plugin configuration like this:

<phase>process-classes</phase>

Since the shade plugin definition comes before the bundle plugin definition in the pom file, the shade plugin will run before the bundle plugin during the process-classes phase.

Holna answered 28/8, 2013 at 19:55 Comment(1)
Unfortunately that doesn't work. It fails with something like this Failed to execute goal org.apache.maven.plugins:maven-shade-plugin:2.1:shade (default) on project modelmapper: Failed to create shaded artifact, project main artifact does not exist.Adahadaha
O
0

There is a neat transformer implementing just this functionality from Hazelcast - HazelcastManifestTransformer (ver 3.9). What it does is thoughtfully merging the Import-Package and Export-Package attributes, enabling the user to exclude extend/reduce the default merged result.

How to use it in your pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>3.1.0</version>
  <dependencies>
    <dependency>
      <groupId>com.hazelcast</groupId>
      <artifactId>hazelcast-build-utils</artifactId>
      <version>3.9</version>
    </dependency>
  </dependencies>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <transformers>
          <transformer implementation="com.hazelcast.buildutils.HazelcastManifestTransformer">
            <mainClass>...</mainClass>
            <!-- the tag below is required due to a missing null-check it seems -->
            <overrideInstructions></overrideInstructions>
      </configuration>
    </executions>
</plugin>

The override instructions (Export/Import-Package) are comma delimited package names, preceded with an exclamation mark whenever we want to exclude those specific ones from the list.

Hope this helps! I do realize that's an old question, but seems the Hazelcast's transformer isn't gaining much publicity.

Oral answered 24/11, 2017 at 14:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.