views:

390

answers:

4

I have a jar file I produced from compiled class files using an ant file with <javac target="1.5" ... /> and I would like to verify that it actually produces 1.5 code. Is there a way to do this?

My version of MATLAB one one of the computers I'm using, uses a JRE 1.5; so it will not run code unless it is JRE 1.5 compatible. It's worked fine with most JAR files I've produced, but I have one that's acting up, with an odd error:

>> s = javaObject('com.example.test.hdf5.Test1');
??? Error using ==> javaObject
No constructor with appropriate signature exists
in Java class com.example.test.hdf5.Test1

even though here's my class, and it has a regular old no-arg constructor:

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();
      System.out.println("Success!");
     }
     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);
      System.out.println("Success!");
     }
     catch (HDF5LibraryException e) {
      throw new RuntimeException(e);
     }
     catch (NullPointerException e) {
      throw new RuntimeException(e);
     }
    }
}

Another file produced in the same package + jar file works fine:

package com.example.test.hdf5;

public class Test3 {
    public Test3() {}

    private int x=0;

    public int foo() { return ++this.x; }
}

and I'm wondering if there's something that's screwing up the compiler's 1.5-ness by importing a library that may not be 1.5-compatible.


update: both my Test1 and Test3 classes are 1.5 (major=0, minor=49 as per javap -v). I added a Test2.java which is the exact same as Test1 but with the body of the methods commented out, so it has the same signatures. I get the following with javap -s:

C:\proj\java\test-hdf5\dist>javap -s -classpath test-hdf5.jar com.example.test.hdf5.Test1
Compiled from "Test1.java"
public class com.example.test.hdf5.Test1 extends java.lang.Object{
public com.example.test.hdf5.Test1();
  Signature: ()V
public static void main(java.lang.String[]);
  Signature: ([Ljava/lang/String;)V
public void testH5File(java.lang.String);
  Signature: (Ljava/lang/String;)V
public void testH5F(java.lang.String);
  Signature: (Ljava/lang/String;)V
}


C:\proj\java\test-hdf5\dist>javap -s -classpath test-hdf5.jar com.example.test.hdf5.Test2
Compiled from "Test2.java"
public class com.example.test.hdf5.Test2 extends java.lang.Object{
public com.example.test.hdf5.Test2();
  Signature: ()V
public static void main(java.lang.String[]);
  Signature: ([Ljava/lang/String;)V
public void testH5File(java.lang.String);
  Signature: (Ljava/lang/String;)V
public void testH5F(java.lang.String);
  Signature: (Ljava/lang/String;)V
}


C:\proj\java\test-hdf5\dist>javap -s -classpath test-hdf5.jar com.example.test.hdf5.Test3
Compiled from "Test3.java"
public class com.example.test.hdf5.Test3 extends java.lang.Object{
public com.example.test.hdf5.Test3();
  Signature: ()V
public int foo();
  Signature: ()I
}

I guess there's just something really weird going on in the HDF5 library JHDF5.jar that causes MATLAB to reject my Test1 class.

update 2 >:( >:( >:( The JHDF5.jar file has version 50 (JRE1.6), so that's probably what's causing me to lose. Phooey to Matlab for not producing a meaningful error message, and Phooey to HDF5 for compiling with JRE1.6 instead of 1.5 or earlier; I'm very doubtful they're using any of the 1.6 features. I'll file a bug report.

+2  A: 

Try methodsview('com.example.test.hdf5.Test1') to see exactly what Matlab thinks your constructor expects.

Supertux
Bizarre. methodsview works on Test3 but not on Test1 (No class com.example.test.hdf5.Test1 can be located or no methods for class com.example.test.hdf5.Test1) even though javap -s shows methods being there....
Jason S
+5  A: 

To determine the Java bytecode version of a class file, use javap -v <classname>. This will output something like

minor version: 0
major version: 49

Major version 49 is Java platform version 1.5 (48 is 1.4, 50 is 1.6)

Martin v. Löwis
is there a way to do this on a JAR file?
Jason S
OK, I figured it out, you just use the -classpath {my JAR file} option
Jason S
Hmm. I get the answer I wanted from this question, (Test1 and Test3 are both version 49) even hough it didn't solve my problem. I'll accept this answer shortly.
Jason S
A: 

This may be a shot in the dark, but did you make any modifications to Test1 while MATLAB was still running? If so, you may have to use the CLEAR command:

clear java

From the CLEAR documentation:

Issue a clear java command after modifying any files on the Java dynamic class path.

gnovice
Shot in the dark appreciated. I've been diligent, both about executing "clear java" and doing clean builds in ant.
Jason S
@Jason: I figured you probably had it covered, but thought I would suggest it anyway just to rule out the simplest fix. You know what they say... "Always check that it's plugged in and the power is on." ;)
gnovice
A: 

This site indicates that

Typically, you do not need to use javaObject. Use the default MATLAB syntax for instantiating a Java class instead. Use javaObject for the cases described above.

So, instead of using javaObject, which creates instances reflectively, you can, if you know the class you are going to create, just use the constructor syntax:

s = com.example.test.hdf5.Test1()

Does this work?

pmf
Both work using reflection (runtime instantiation cannot work any other way), it's just that javaObject is explicit. I always use it for anything other than the java.* classes. MATLAB seems to have a problem recognizing classnames in that fashion unless they start with "java." -- I saw the webpage that says "Typically, you do not need to use javaObject" and in most cases it's just wrong.
Jason S
Hmm. I just tried it on R2009a and it works equally as well as the javaObject() syntax. The difference is that if you try to instantiate something not on the classpath, you get a clearer error message with javaObject().
Jason S
example: (this won't format well in comments) >> s1 = javaObject('com.nonexistent.SwizzleStick');??? Error using ==> javaObjectNo class com.nonexistent.SwizzleStick can be located on Java class path >> com.nonexistent.SwizzleStick??? Undefined function or variable 'com'.
Jason S