Maven: Bundling and Unpacking Native Libraries

Introduction

Steps to bundle the native libraries to be pushed to Nexus, and to unpack the native libraries on mvn package.

Bundling Native Libraries into a JAR File

Let’s assume we have the following native libraries for multiple platforms:-

tree native

native
├── linux
│   ├── x86
│   │   └── libnative_synchronization.so
│   └── x86_64
│       └── libnative_synchronization.so
├── macosx
│   └── libnative_synchronization.jnilib
└── win32
    ├── x86
    │   └── native_synchronization.dll
    └── x86_64
        └── native_synchronization.dll

Create a jar that contains these native libraries. The -C options prevents the native folder from being created in the JAR file.

jar cMf my-project-native.jar -C native .

Pushing JAR to Nexus

When pushing this native JAR file to Nexus, make sure to use the natives-* classifier. In this example, I called it natives-all.

<dependency>
	<groupid>my.project</groupid>
	<artifactid>native</artifactid>
	<version>1.0</version>
	<classifier>natives-all</classifier>
</dependency>

Configuring pom.xml

First, add LWJGL and the native JAR dependencies.

<dependencies>
    <dependency>
        <groupid>org.lwjgl.lwjgl</groupid>
        <artifactid>lwjgl</artifactid>
        <version>2.9.3</version>
    </dependency>
    <dependency>
		<groupid>my.project</groupid>
		<artifactid>native</artifactid>
		<version>1.0</version>
		<classifier>natives-all</classifier>
    </dependency>
</dependencies>

Then, add the following plugin:-

<build>
    <plugins>
		<plugin>
		    <groupid>com.googlecode.mavennatives</groupid>
		    <artifactid>maven-nativedependencies-plugin</artifactid>
		    <version>0.0.7</version>
		    <executions>
		        <execution>
		            <id>unpacknatives</id>
		            <phase>generate-resources</phase>
		            <goals>
		                <goal>copy</goal>
		            </goals>
		        </execution>
		    </executions>
		</plugin>
    </plugins>
</build>

This plugin searches for dependencies with natives-* classifier and unpacks the content to target/natives folder.

Testing

Run mvn clean package.

Inspect target/natives. The native libraries should be unpacked here:-

target/natives
├── META-INF
│   └── MANIFEST.MF
├── OpenAL32.dll
├── OpenAL64.dll
├── jinput-dx8.dll
├── jinput-dx8_64.dll
├── jinput-raw.dll
├── jinput-raw_64.dll
├── jinput-wintab.dll
├── libjinput-linux.so
├── libjinput-linux64.so
├── libjinput-osx.jnilib
├── liblwjgl.dylib
├── liblwjgl.so
├── liblwjgl64.so
├── libopenal.so
├── libopenal64.so
├── linux
│   ├── x86
│   │   └── libnative_synchronization.so
│   └── x86_64
│       └── libnative_synchronization.so
├── lwjgl.dll
├── lwjgl64.dll
├── macosx
│   └── libnative_synchronization.jnilib
├── openal.dylib
└── win32
    ├── x86
    │   └── native_synchronization.dll
    └── x86_64
        └── native_synchronization.dll

Maven Archetype Plugin: Velocity Variable Substitutions Not Resolving

PROBLEM

Let’s assume we have the following package.json in our archetype:-

{
  &quot;name&quot;: &quot;${rootArtifactId}&quot;,
  &quot;private&quot;: true,
  &quot;devDependencies&quot;: {
    ...
  }
}

When creating a project from this archetype, the Velocity variable substitution for ${rootArtifactId} doesn’t resolve at all.

SOLUTION

After reading Maven Archetype Plugin’s source code here and here, the Velocity variable substitutions are only performed on the following file extensions:-

List&lt;String&gt; DEFAULT_FILTERED_EXTENSIONS =
    Arrays.asList(
        new String[]
            {
                &quot;java&quot;, &quot;xml&quot;, &quot;txt&quot;, &quot;groovy&quot;, &quot;cs&quot;, &quot;mdo&quot;, &quot;aj&quot;, &quot;jsp&quot;, &quot;gsp&quot;, 
                &quot;vm&quot;, &quot;html&quot;, &quot;xhtml&quot;, &quot;properties&quot;, &quot;.classpath&quot;, &quot;.project&quot;
            }
    );

In another word, if we have these variables in JSON or JavaScript files, they will not resolved at all.

To fix this, define the needed file extensions in Maven Archetype Plugin configuration:-

&lt;plugin&gt;
    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
    &lt;artifactId&gt;maven-archetype-plugin&lt;/artifactId&gt;
    &lt;version&gt;2.3&lt;/version&gt;
    &lt;configuration&gt;
        &lt;archetypeFilteredExtentions&gt;js,json,md,java,xml,txt,groovy,jsp,vm,html,properties&lt;/archetypeFilteredExtentions&gt;
    &lt;/configuration&gt;
&lt;/plugin&gt;

Maven Archetype Plugin: Failed to execute goal org.apache.maven.plugins:maven-archetype-plugin:2.3:create-from-project

PROBLEM

When running mvn archetype:create-from-project with Maven Ear Plugin defined under <pluginManagement>….

&lt;project ...&gt;
    ...
    &lt;build&gt;
        &lt;pluginManagement&gt;
                &lt;plugin&gt;
                    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                    &lt;artifactId&gt;maven-archetype-plugin&lt;/artifactId&gt;
                    &lt;version&gt;2.3&lt;/version&gt;
                &lt;/plugin&gt;

                &lt;plugin&gt;
                    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                    &lt;artifactId&gt;maven-ear-plugin&lt;/artifactId&gt;
                    &lt;version&gt;2.10.1&lt;/version&gt;
                &lt;/plugin&gt;
            &lt;/plugins&gt;
        &lt;/pluginManagement&gt;
    &lt;/build&gt;
&lt;/project&gt;

… the following exception occurs…

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-archetype-plugin:2.3:create-from-project (default-cli) on project myproject-webapp: null: MojoFailureException -&gt; [Help 1]
org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal org.apache.maven.plugins:maven-archetype-plugin:2.3:create-from-project (default-cli) on project myproject-webapp: null
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:212)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:116)
        at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:80)
        at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:51)
        at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:120)
        at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:355)
        at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:155)
        at org.apache.maven.cli.MavenCli.execute(MavenCli.java:584)
        at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:216)
        at org.apache.maven.cli.MavenCli.main(MavenCli.java:160)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
        at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
        at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
        at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
Caused by: org.apache.maven.plugin.MojoFailureException
        at org.apache.maven.archetype.mojos.CreateArchetypeFromProjectMojo.execute(CreateArchetypeFromProjectMojo.java:258)
        at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:132)
        at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
        ... 19 more

SOLUTION

It appears this problem happens when using Maven Archetype Plugin 2.3, but works fine when using 2.2.

To fix this, define an empty <modules> under <configuration> to prevent NullPointerException.

&lt;project ...&gt;
    ...
    &lt;build&gt;
        &lt;pluginManagement&gt;
                &lt;plugin&gt;
                    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                    &lt;artifactId&gt;maven-archetype-plugin&lt;/artifactId&gt;
                    &lt;version&gt;2.3&lt;/version&gt;
                &lt;/plugin&gt;

                &lt;plugin&gt;
                    &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                    &lt;artifactId&gt;maven-ear-plugin&lt;/artifactId&gt;
                    &lt;version&gt;2.10.1&lt;/version&gt;
                    &lt;configuration&gt;
                        &lt;modules/&gt;
                    &lt;/configuration&gt;
                &lt;/plugin&gt;
            &lt;/plugins&gt;
        &lt;/pluginManagement&gt;
    &lt;/build&gt;
&lt;/project&gt;