JNA 3.4.0 on the NetBeans Platform

This is a little problem that’s been bugging me for a while – how to use a newer version of JNA (Java Native Access) with a NetBeans platform application.  The recently released JNA 3.4.0 brings some major performance improvements for callbacks, and as this improvement was requested by me (particularly for JNAJack) I’m damn well going to use it! :-)

UPDATE 21/6/12 – after reading this be sure to read JNA 3.4.x on the NetBeans Platform (revisited) which covers in more detail some of the questions in the comments here.

So, what’s the problem?

Well,

  • JNA is in the platform, but it’s an old version.
  • A number of platform modules require JNA.
  • JNA includes a native library, which precludes having multiple versions of JNA in the module system.
  • JNA in the platform only allows friend dependencies (don’t get me started on the annoyance of friend dependencies on modules that provide native libs!)

And, the solution -

  • Create a new library wrapper module for JNA 3.4.0. Give the wrapper module the same code name base as the core JNA module – org.netbeans.libs.jna
  • Give the new wrapper module the same major release version as the platform JNA (1), and a specification version higher than the platform JNA (I chose 3.4.0 as the logical choice)
  • Make sure JNA is enabled in the platform. This confused me for a while, but the excluded modules list has no sense of clusters, so if you exclude JNA from the platform, your new module will also be excluded!  (that would probably make a good RFE)
  • Make sure you’ve got a module in your application that has a dependency on the new JNA module (ie. depends on version 3.4.0).  Not sure how necessary this is, but it seems to ensure the right module is loaded, and you’ll need the dependency to rely on the new features anyway.

Run your application and look at the module list in the log.  You should see the new version of JNA being loaded.

So, are we done?

Well, not quite.  This allows us to run our application from the IDE with the new JNA module.  However, if you build a zip distribution you’ll notice that the old JNA module is still in the platform folder.  It shouldn’t cause a problem, but it takes up space and for safety’s sake it would be better to get rid of it.

To do that, I copied the build-zip target from the build harness into the build.xml file of my application, and made a few changes (see comment).

<target name="build-zip" depends="build,build-launchers" description="Builds a ZIP distribution of the suite, launchers, and selected modules from the platform.">
  <mkdir dir="${dist.dir}"/>
  <!-- pathfileset does not support 'prefix' and 'filemode' parameters,
       we have to copy them to temp location -->
  <tempfile property="temp.dir.nbexec" destdir="${suite.build.dir}" deleteonexit="true" prefix="nbexec"/>
  <tempfile property="temp.dir.rest" destdir="${suite.build.dir}" deleteonexit="delete" prefix="rest"/>
  <subant genericantfile="${harness.dir}/suite.xml" target="copy-cluster" inheritrefs="true">
    <property name="dest.dir" value="${temp.dir.rest}"/>
    <property name="nbexec.dir" value="${temp.dir.nbexec}"/>
    <property name="build.dir" value="${suite.build.dir}"/>
    <resources refid="zip.platform.clusters"/>
  </subant>
  <zip destfile="${dist.dir}/${app.name}.zip">
    <zipfileset dir="${build.launcher.dir}/bin/" filemode="755" prefix="${app.name}/bin"/>
    <zipfileset dir="${build.launcher.dir}/etc/" prefix="${app.name}/etc"/>
    <zipfileset dir="${temp.dir.nbexec}" filemode="755" prefix="${app.name}"/>
    <zipfileset dir="${temp.dir.rest}" prefix="${app.name}">
      <!-- FOLLOWING THREE LINES REMOVE JNA FROM PLATFORM -->
      <exclude name="platform/**/org-netbeans-libs-jna*"/>
      <exclude name="platform/**/jna-3.2.7.jar"/>
      <exclude name="platform/**/*jnidispatch*"/>
    </zipfileset>

    <!-- Yes, the doubled app.name is a bit ugly, but better than the alternative; cf. #66441: -->
    <zipfileset dir="${cluster}" prefix="${app.name}/${app.name}">
      <exclude name="config/Modules/*.xml_hidden"/>
    </zipfileset>
  </zip>
</target>

In particular, notice the three exclude lines that match various artefacts of the JNA module and exclude them from the zip file (and therefore also from the installers).

This all seems to be working fine, and will be used in the (slightly late) first full release of Praxis, which is based on NetBeans platform 7.0.  It may require tweaking to work with other versions of the platform.