A few days ago I consulted to a company that wanted to integrate some of their Java code in Matlab. The Java code compiled ok and ran just fine in the Java environment, but when we wanted to use the relevant Java classes in Matlab we got all sorts of errors. Since I believe that this could be a common problem, and I’m not sure that there’s any other place that does this, I thought to list the possible error causes in today’s article:
- Forgetting or mistyping the package name:
>> jObject = JButton('Click me!'); % missing package name Undefined function 'JButton' for input arguments of type 'char'. >> jObject = java.swing.JButton('Click me!'); % should be javax.swing... Undefined variable "java" or class "java.swing.JButton". >> jObject = javax.Swing.JButton('Click me!'); % should be javax.swing... Undefined variable "java" or class "javax.Swing.JButton". >> import java.swing.* % should be javax.swing... - no error here, only in the next line >> jObject = JButton('Click me!'); % missing package name Undefined function 'JButton' for input arguments of type 'char'. >> import java.swing.JButton % should be javax.swing... Error using import Import argument 'java.swing.JButton' cannot be found or cannot be imported.
Note: package names are typically lowercase, but 3rd-party packages might not follow this convention! Since Java is case-sensitive, the package name must be exact.
- Mistyping the class name. As with package names, Java class names are also case-sensitive. Beware of cases of O/0 (capital-“o” vs. the digit zero), and I/l/1 (capital-“i” vs. lowercase “L” vs. the digit 1). Also note whether the class name includes the underscore (“_”) character.
- Using a Java class that was compiled using a newer JDK major-version than the JVM used in Matlab. The specific JVM used by Matlab varies across platforms and Matlab releases. On R2014a Win64, the default (pre-installed) version is 1.7, which means that classes compiled using (or targeting) JDK 7 or below are ok, but classes compiled using JDK 8 or above would simply not run:
>> a = MyJavaClass; Undefined function or variable 'MyJavaClass'. >> a = my.java.Class; Undefined variable "my" or class "my.java.Class".
To get Matlab’s current JVM version, use the version command:
>> version -java ans = Java 1.7.0_11-b21 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
The default JVM used in Matlab R14 (7.0) to R2013a (8.1) was 1.6 (=JDK 6); R2013b (8.2) and later use 1.7 (=JDK 7). If you wish to ensure compatibility with earlier Matlab releases, I suggest compiling using JDK 6 rather than 7 or 8. This can easily be modified in all Java IDEs, in the project’s preferences. Remember to reference the corresponding JRE 1.6 libraries as well, rather than the newer JRE ones. In many cases, the Java code would still compile and run properly, even when compiled using the earlier JDK/JRE.
If downgrading the compilation JDK is not possible (for example, if you do not have access to the source code, or if it uses some new JDK features), then consider installing a newer compatible JVM in Matlab.
Note that when we try running the Java classes using the java executable (outside Matlab), we do get a meaningful message about the fact that the classes were compiled for a higher JVM version. Unfortunately, this information is simply not being provided by Matlab – just the standard plain error about the function or file not being found. I hope this will be fixed in some future Matlab release.
- Forgetting to update the Java classpath. Java has a different classpath than Matlab’s. Class or JAR files placed on Matlab’s path are not recognized. Instead, these files need to be added to the Java classpath, either dynamically within the Matlab session (using the javaaddpath function), or statically (by adding entries to the classpath.txt or javaclasspath.txt files). Read here for additional details. Note that the javaclasspath.txt alternative only exists since R2012b (8.0). You can view the current Java classpath in Matlab using the javaclasspath command.
When updating the Java classpath, either dynamically or statically, beware of the following pitfalls:
- If you add a folder name to the javaclasspath, then all *.class files are automatically recognized and they will be loaded when first used. However, this does NOT include *.jar or *.zip files placed in these folders. The Java specification requires such files to be added individually to the classpath, using their full pathname.
- While we can use relative paths when adding elements dynamically (using javaaddpath), we must specify the full pathname when updating the static classpath files.
- Dependency #1: A class that depends on any other class that is not on the current Java classpath (either dynamic or static). This is typically due to the fact that the class was compiled in a Java IDE where there were multiple referenced libraries, which were not copied to the Matlab classpath. It is not enough to simply place the generated output *.class or *.jar files in Matlab’s Java classpath – the referenced libs must also be placed there. If they are not, then Matlab simply issues the generic error that the function or class cannot be found. Matlab provides no information that this is a dependency error and we must infer this ourselves. Note that it does not matter that the non-existent class might referenced in an obscure portion of the class code that is never reached – the mere fact that there is a reference in the class that cannot be located causes the entire class to fail to load. Debugging this can indeed be nerve wrecking (and another example)… I hope that this too will be fixed in some future Matlab release.
- Dependency #2: A class on the static Java classpath that depends on another class which is on the dynamic Java classpath. All static classes must depend only on other static classes, since the static classpath is processed before the dynamic one, when the JVM is launched at Matlab startup.
- Non-public class – Matlab can only access
publicclasses. If the class is
protectedor has package visibility (by not specifying any visibility modifier at all), then the class would not be loadable by Matlab, only by other Java classes. So remember to add the
publickeyword in the definition of all the Java classes that you wish to directly use in Matlab.
- Non-public constructor – Matlab can only create objects for non-static classes that have
publicconstructors. If all the class constructors are non-
public, then Matlab cannot create a class instance object. In such a case we would get a misleading error message, that at least hints that the problem is with the constructor:
>> jObject = MyJavaClass(); No constructor 'MyJavaClass' with matching signature found.
Note that using private constructors is common practice for singleton designs. In such cases we might find a
public staticclass method that returns the class reference (e.g., MyJavaClass.getInstance()).
- Non-matching constructor – This is a variation of the previous pitfall. In this case, we try to invoke a class constructor with input parameters that do not match the declaration. A typical example of this is when the constructor is declared to accept an
int, and we try to pass a standard Matlab number (which is a double). In such cases, a simple solution could be to either modify the class, overloading the constructor to also accept double, or to type-cast the inputs in Matlab to the relevant type expected by a constructor:
jObject = MyJavaClass(int32(value));
Any other pitfalls I forgot to mention? Let us know in a comment below.
p.s. – the javaclasspath function has an undocumented input parameter: specifying -v0, -v1 or -v2 sets the Java classloader’s verbosity level to the relevant value. If you don’t know what this means, then you probably don’t need to use this feature…