Ensure all referenced libraries are on the CLASSPATH
Troubleshooting Forge ClassLoaders
If you are experiencing ClassLoader issues, when loading or running your Plugin (but not during unit tests), the cause might be the ClassLoading structure of JBoss Forge versions 1.3.2.Final and earlier. This is typically the case if your the Maven project implementing your Plugin uses Maven dependencies. In these cases, you could configure Forge to use an alternate Plugin ClassLoading strategy, activated by setting a flag in your Plugin’s src/main/resources/META-INF/forge.xml file:
<forge>
<dependencies-as-resource-root/>
</forge>
This will cause Forge to bundle all dependencies for your Plugin in the Plugin module itself, instead of creating a separate “dependencies” module, with a separate ClassLoader.
Note! When you configure Forge to use the “dependencies-as-resource-root” option, your project must explicitly import any transitive Maven dependencies, as the Forge ClassLoader structure prevents transitive dependencies to be “seen” by your plugin. A good help to find all transitive dependencies is the “mvn dependency:tree” command, which should be run in your Plugin’s Maven project.
As a last resort, you may also shade code into your plugin’s JAR file; however, this is extremely discouraged, since you may cause ClassCastExceptions at runtime, and this increases the burden on Class scanning at boot time, because CDI will scan all classes in your Plugin JAR file.
Using Forge to set up Shading
[example-plugin] example-plugin $ shade setup
***SUCCESS*** Shade plugin is installed.
[example-plugin] example-plugin $
[example-plugin] example-plugin $ shade include commons-collections:commons-collections:3.2.1
Notice that the pom.xml file has been modified and now includes a shade configuration including commons-collections.
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>commons-collections:commons-collections</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
It it also recommended, however, to relocate shaded class files to a new package. Your code will access the bundled code at this new location, and will prevent version conflicts if another plugin bundles a different version of the same library. For this, we use the following command.
$ shade relocate --pattern {ORIGINAL PGK} --shadedPattern {NEW PKG} --excludes {EXCLUDED PKGS...}
For the purposes of this example, let us assume that our Plugin depends on the Apache Commons Collections library (org.apache.commons.collections), and we want to make sure that no conflicts occur.
[example-plugin] example-plugin $ shade relocate --pattern org.apache.commons.collections --shadedPattern ~.shaded.apache.collections
***SUCCESS*** Relocating [org.apache.commons.collections] to [com.example.forge.plugin.shaded.apache.collections]
[example-plugin] example-plugin $
This should be repeated for each dependency as necessary. Notice that our POM has been updated with the configuration:
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>commons-collections:commons-collections</include>
</includes>
</artifactSet>
<relocations>
<relocation>
<pattern>org.apache.commons.collections</pattern>
<shadedPattern>com.example.forge.plugin.shaded.apache.collections</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
When you build your plugin, you should see confirmation output from the Maven Shade Plugin looking something like this:
[INFO] --- maven-shade-plugin:1.4:shade (default) @ example-plugin ---
[INFO] Excluding org.jboss.seam.forge:forge-shell-api:jar:{version} from the shaded jar.
[INFO] Excluding org.jboss.seam.forge:forge-parser-java-api:jar:{version} from the shaded jar.
[INFO] Excluding org.jboss.seam.forge:forge-parser-xml:jar:{version} from the shaded jar.
[INFO] Excluding org.jboss.shrinkwrap.descriptors:shrinkwrap-descriptors-api:jar:{version} from the shaded jar.
[INFO] Excluding javax.enterprise:cdi-api:jar:{version} from the shaded jar.
[INFO] Excluding org.jboss.spec.javax.interceptor:jboss-interceptors-api:jar:{version} from the shaded jar.
[INFO] Excluding javax.annotation:jsr250-api:jar:{version} from the shaded jar.
[INFO] Excluding javax.inject:javax.inject:jar:{version} from the shaded jar.
[INFO] Including commons-collections:commons-collections:jar:3.2.1 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing ~/Desktop/example-plugin/target/example-plugin-1.0.0-SNAPSHOT.jar
with ~/Desktop/example-plugin/target/example-plugin-1.0.0-SNAPSHOT-shaded.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Default dependencies
During plugin installation, Forge adds certain modules as dependencies to the plugin module. Forge adds the org.jboss.forge.javaee.api
, org.jboss.forge.maven.api
, org.jboss.forge.scaffold.api
, org.jboss.forge.shell.api
, org.jboss.seam.render
and javax.api
modules as dependencies to your plugin. These modules already exist in a Forge installation and are added as dependencies to the plugin module, so they’re readily available during plugin execution.
If you chose to use the default plugin packaging mode, Forge creates an additional ‘dependencies’ module as a dependency for your plugin during installation. The ‘dependencies’ module contains all the dependencies with an effective scope of runtime, that are present anywhere in the dependency hierarchy of your plugin project. The artifacts constituting the dependencies are added as resource roots to the ‘dependencies’ module. In general, project POM dependencies with org.jboss.forge
groupId will be omitted from the ‘dependencies’ module.