tags:

views:

493

answers:

4

Anyone out there used MATLAB's javaObject() function with a JAR file that uses JNI?

I'm trying to get JHDF5 running and it seems like it bombs when it tries to get access using jhdf5.dll so I don't really know what to do next. :(

edit: I am NOT trying to read basic HDF5 files. I have my own custom Java code that does something with HDF5 and needs the JHDF5 library. Also, my first question is just whether anyone has used it successfully at all. If not then I'm probably fighting a losing battle. If so then at least it gives me hope. I'll try to debug, it's very difficult compared to debugging regular Java code under Eclipse.

update: ok, specifics below. I made a very short test class and it has the same failure modes as my complicated program. It looks like my Java classes can't access the HDF5 static constants for some reason.

My MATLAB javaclasspath is set to include my test-hdf5.jar with Test1.java (below), and the files jhdf5.jar, jhdf5.dll, jhdf5obj.jar, and jhdfobj.jar in the same directory.

source file Test1.java:

package com.example.test.hdf5;

import ncsa.hdf.hdf5lib.H5;
import ncsa.hdf.hdf5lib.HDF5Constants;
import ncsa.hdf.hdf5lib.exceptions.HDF5LibraryException;
import ncsa.hdf.object.FileFormat;
import ncsa.hdf.object.h5.H5File;

public class Test1 {
    public Test1 () {}

    public static void main(String args[])
    {
     Test1 test = new Test1();
     if (args.length < 2)
     {

     }
     else if ("h5file".equals(args[0]))
     {
      test.testH5File(args[1]);
     }
     else if ("h5f".equals(args[0]))
     {
      test.testH5F(args[1]);   
     }
    }


    public void testH5File(String filename) {
     H5File file;
     try
     {
      file = (H5File) new H5File().createFile(
        filename, FileFormat.FILE_CREATE_OPEN);
      file.close();
     }
     catch (Exception e)
     {
      throw new RuntimeException(e);
     }
    }

    public void testH5F(String filename) {
     try {
      int id = H5.H5Fopen(filename, 
        HDF5Constants.H5F_ACC_RDONLY, HDF5Constants.H5P_DEFAULT);
      H5.H5Fclose(id);
     }
     catch (HDF5LibraryException e) {
      throw new RuntimeException(e);
     }
     catch (NullPointerException e) {
      throw new RuntimeException(e);
     }
    }
}

MATLAB error:

>> T=javaObject('com.example.test.hdf5.Test1')

T =

com.example.test.hdf5.Test1@c9a375

>> T.testH5F('c:/tmp/espdf/jj11copy.hdf5')
java.lang.UnsatisfiedLinkError: no jhdf5 in java.library.path
    at java.lang.ClassLoader.loadLibrary(Unknown Source)
    at java.lang.Runtime.loadLibrary0(Unknown Source)
    at java.lang.System.loadLibrary(Unknown Source)
    at ncsa.hdf.hdf5lib.H5.<clinit>(H5.java:276)
    at ncsa.hdf.hdf5lib.HDF5Constants.<clinit>(HDF5Constants.java:494)
    at com.example.test.hdf5.Test1.testH5F(Test1.java:46)
Jul 23, 2009 10:38:16 AM ncsa.hdf.hdf5lib.H5 <clinit>

INFO: HDF5 library: jhdf5 resolved to: jhdf5.dll;  NOT successfully loaded from java.library.path

??? Java exception occurred:
java.lang.UnsatisfiedLinkError: ncsa.hdf.hdf5lib.H5.H5dont_atexit()I

    at ncsa.hdf.hdf5lib.H5.H5dont_atexit(Native Method)

    at ncsa.hdf.hdf5lib.H5.<clinit>(H5.java:288)

    at ncsa.hdf.hdf5lib.HDF5Constants.<clinit>(HDF5Constants.java:494)

    at com.example.test.hdf5.Test1.testH5F(Test1.java:46)


>> T.testH5F('c:/tmp/espdf/jj11copy.hdf5')
??? Java exception occurred:
java.lang.NoClassDefFoundError: Could not initialize class ncsa.hdf.hdf5lib.HDF5Constants

    at com.example.test.hdf5.Test1.testH5F(Test1.java:46)


>> T.testH5File('c:/tmp/espdf/jj11copy.hdf5')
??? Java exception occurred:
java.lang.NoClassDefFoundError: Could not initialize class ncsa.hdf.hdf5lib.HDF5Constants

    at ncsa.hdf.object.h5.H5File.<init>(H5File.java:167)

    at ncsa.hdf.object.h5.H5File.<init>(H5File.java:106)

    at com.example.test.hdf5.Test1.testH5File(Test1.java:34)

in case it matters, here's the ant build file I'm using. The JHDF5 .jar files and .dll are in my lib directory; they get copied to the dist directory where my own .jar file is created.

<?xml version="1.0"?>
<project default="all" name="test-hdf5">
  <description>some libraries to use later</description>

  <property name="srcDir" location="src"/>
  <property name="buildDir" location="bin"/>
  <property name="distDir" location="dist"/>
  <property name="libDir" location="lib"/>

  <target name="init">
    <tstamp/>
    <mkdir dir="${buildDir}"/>
    <mkdir dir="${distDir}"/>
  </target>
      <path id="antclasspath">
        <fileset dir="${libDir}">
            <include name="*.jar"/>
        </fileset>
    </path>  

    <target name="compile" depends="init">
        <javac srcdir="${srcDir}"
               destdir="${buildDir}"
               debug="on"
               target="1.6"
               classpathref="antclasspath"
        />
      </target>

  <target name="dist" depends="compile">
    <copy todir="${buildDir}">
     <fileset dir="${srcDir}">
      <include name="*.properties" />
     </fileset>
    </copy>
    <copy todir="${distDir}">
       <fileset dir="${libDir}">
           <include name="*.dll" />
           <include name="*.jar" />
       </fileset>
    </copy>
    <jar destfile="${distDir}/test-hdf5.jar" basedir="${buildDir}"
        includes="**">
      <manifest>
        <attribute name="Built-By" value="${user.name}"/>
     <attribute name="Main-Class" value="com.example.test.hdf5.Test1" />
     <attribute name="Class-Path" value=". ./jhdf5.jar ./jhdfobj.jar ./jdhf5obj.jar" />
      </manifest>
    </jar>
  </target>

  <target name="all" depends="dist" />

  <target name="clean" >
    <delete dir="${buildDir}" />
  </target>
</project>
A: 

The dll is probably not on the java class path. Try adding it's directory to the system's PATH environment variable. Or better yet, just use the hd5read/write functions.

Mike Katz
This isn't it; I can run my .jar file from a command prompt or in the Eclipse debugger. And I tried putting a copy of the DLL into a directory on the path, that didn't change anything.
Jason S
A: 

The classpath is not used for dlls. They need to be in the PATH environment variable (windows) or LD_LIBRARY_PATH (linux). You might also want to verify that the relative locations and dependencies of the DLLs themselves are correct using Depends (Windows, http://www.dependencywalker.com) or ldd (linux)

gibbss
This isn't it; I can run my .jar file from a command prompt or in the Eclipse debugger.
Jason S
+1  A: 

JHDF5 uses some goofy search logic at the Java side for loading the dll. It works, except when it doesn't, which is often. And as with many HDF5 details, the underlying logic is undocumented.

I did this: took JHDF5 Java sources, removed the stupid AI that tries to load the jhdf5.dll (it's in ncsa/hdf/hdf5lib/H5.java file, the static section in about lines 230-290), and replaced it with an explicit System.load("full/path/to/the/jhdf5.dll"); statement. Then recompiled the jhdf5.jar. Maybe not beautiful, but works perfectly.

Additionally, looking at the source, it seems that if you set an system property called H5_LIBRARY_NAME_PROPERTY_KEY to point at the dll, it might get loaded. You can set system properties for instance by starting jvm with a -D switch, something like:

java -DH5_LIBRARY_NAME_PROPERTY_KEY=path/to/the/jhdf5.dll -jar yourapp.jar

Didn't try it, though.

Joonas Pulakka
Unfortunately in MATLAB you don't start the jvm, it does on its own. I have no idea how to set system properties, if I can at all.
Jason S
Ah. Duh. I can just do java.lang.System.setProperty('ncsa.hdf.hdf5lib.H5.hdf5lib',path_to_jhdf5_dll); That works!
Jason S
+2  A: 

Matlab is very complicated about this, the above are correct that the classpath is not used for dlls. You may use an envirnomental solution like the above, but a more MATLAB specific variable is available too. The file librarypath.txt is able list folders containing any dll's available to MATLAB. It is executed at startup time, so cannot be added to dynamically. To edit the library path, run edit librarypath.txt on the MATLAB command line.

Ryan