- Undocumented Matlab - https://undocumentedmatlab.com -

Java class access pitfalls

Posted By Yair Altman On July 2, 2014 | 8 Comments

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:

  1. 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.

  1. 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.
     
  2. 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 [1].
    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.

  3. 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 [2] function), or statically (by adding entries to the classpath.txt or javaclasspath.txt files, or using these undocumented hacks [3]). Read here [4] for additional details. Note that the javaclasspath.txt alternative only exists since R2012b [5] (8.0). You can view the current Java classpath in Matlab using the javaclasspath [6] 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.

     

  4. 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 [7] (and another example [8])… I hope that this too will be fixed in some future Matlab release.
     
  5. 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.
     
  6. Non-public class – Matlab can only access public classes. If the class is private, protected or 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 public keyword in the definition of all the Java classes that you wish to directly use in Matlab.
     
  7. Non-public constructor – Matlab can only create objects for non-static classes that have public constructors. 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 static class method that returns the class reference (e.g., MyJavaClass.getInstance()).

  8. 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));
  9. Not enough PermGen space – PermGen is the memory area where Java stores the code for its loaded classes. The more classes you load, and the more complex they are, the larger the required PermGen. By default Matlab allocates a relatively small amount of memory to PermGen (32MB for the initial space, with a maximum of 64MB or 128MB – this may change across releases and platforms; see here [9] for various ways to diagnose your specific installation). If you load additional Java classes, you may well run out of PermGen space, even if you increase the total amount of Java heap memory in Matlab’s preferences:
    >> jObject = MyJavaClass();
    Java exception occurred:
    java.lang.OutOfMemoryError: PermGen space
    

    The solution in this case is to create a java.opts file in Matlab’s startup folder, that contains a higher specification of the maximal allowed PermGen space. The java.opts file is a simple text file that is automatically loaded by Matlab [10] when it starts its internal Java engine. For example, to set the initial PermGen space to 64MB and the maximal PermGen space to 256MB, include the following lines in java.opts:

    -XX:PermSize=64m
    -XX:MaxPermSize=256m
    

    An alternative solution that might help in some cases is to load the new classes on Matlab’s static Java classpath, rather than on the dynamic classpath (see item #4 above).

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…

Categories: Java, Low risk of breaking in future versions, Undocumented feature


8 Comments (Open | Close)

8 Comments To "Java class access pitfalls"

#1 Comment By waldroje21 On May 1, 2015 @ 08:22

Any idea why a Matlab would recognize a Java class file from the Dynamic path, but not the Static? I’ve added it to my Static path, and it’s in there… but does not work… when I then add the same path using javaaddpath , it works.

#2 Comment By Yair Altman On May 1, 2015 @ 08:26

Perhaps one or more of the following happened:

* you edited the wrong classpath.txt file
* you forgot to restart Matlab after editing the classpath.txt file
* you mistyped the class’s full path in the file
* you used a relative path in the file

#3 Comment By waldroje21 On May 1, 2015 @ 13:21

in regard to the first… it shows up on the bottom when I type javaclasspath in the workspace, so I assume it can’t be the wrong file, and that path is what i get when i type prefdir… I definitely restarted Matlab…. and I’m using the same exact file string in the Dynamic path, that I use in the javaclasspath.txt, i just copied it straight from terminal. I’ve done this with no problem on 3 other installs, so it’s a bit strange.

#4 Comment By Yair Altman On May 2, 2015 @ 10:18

If you wish me to help you debug your specific installation, contact me by mail for a private consulting.

#5 Comment By Vincent On March 16, 2016 @ 20:38

How about what to do when you get a “java.lang.NoSuchFieldError” because your java code uses a version of Apache’s httpcore that is newer than the one matlab ships with, and the old one seems to be creating conflicts with the newer one you’ve added to your java path?

#6 Comment By Malcolm Lidierth On March 16, 2016 @ 22:26

The class loader will only load one copy of a specific package/class combination. A newer version will not replace the older one even if you have called javaaddpath (hence the NoSuchFieldError which implies you have created an instance using the old code). This is a Java class loader feature: if you load a jar that has dependencies on other jars (e.g. in a /dist/lib folder), and some of those jars are already loaded, the already loaded versions will continue to be used.

In general, open source projects with the Apache brand will maintain backwards compatibility – deprecating, but not removing, old fields/methods. If backwards compatibility is not maintained Apache projects will usually alter the package names so both versions can be used simultaneously. This being the case, replacing the jar file shipped with MATLAB with the newer version should produce no problems. But, anyone else using your code will need to do that too. Buyer beware.

#7 Comment By Amaury Vanvinckenroye On October 19, 2016 @ 14:26

Hi, I’m using some Java classes in a Matlab code and it seems that a specific java class is not loaded, but only at the first run (i.e. at the start of Matlab). Later calls to the java function don’t give any error, even if I “clear all; clear classes; clear java”. Here’s the part of code failing at first run.

javaaddpath(Obj.MongoDBPath)
import java.util.ArrayList;
import java.lang.String;
import com.mongodb.*;

credentialsList = ArrayList();
credentials = MongoCredential.createCredential(Username, 'admin' , password);
credentialsList.add(credentials);
mongoClient = MongoClient(ServerAddress(IP,Port), credentialsList);

The failing java class is ServerAdress and is part of the mongodb package.
Other java classes run fine immediately.
This error doesn’t occur on all computers, so I’m giving you my specs.
Windows 10 (previously windows 8), Matlab R2013a with Java 1.6.0_17-b04 (also tried with Java 1.8.0_25-b18 when adding it as environment variable).
It worked on a Mac with Matlab R2015b with Java 1.7, but also failed on another Mac with Matlab R2014a and java 1.8.
Thanks in advance

#8 Comment By Yair Altman On October 20, 2016 @ 20:29

@Amaury – this seems to be something specific to the MongoClient class. You should probably ask about this in the MongoDB forums.


Article printed from Undocumented Matlab: https://undocumentedmatlab.com

URL to article: https://undocumentedmatlab.com/articles/java-class-access-pitfalls

URLs in this post:

[1] installing a newer compatible JVM in Matlab: http://undocumentedmatlab.com/blog/using-java-7-in-matlab-r2013a-and-earlier

[2] javaaddpath: http://www.mathworks.com/help/matlab/ref/javaaddpath.html

[3] these undocumented hacks: http://undocumentedmatlab.com/blog/static-java-classpath-hacks

[4] Read here: https://www.mathworks.com/help/matlab/matlab_external/java-class-path.html

[5] only exists since R2012b: http://undocumentedmatlab.com/blog/matlab-installation-take-2

[6] javaclasspath: http://www.mathworks.com/help/matlab/ref/javaclasspath.html

[7] indeed be nerve wrecking: https://www.mathworks.com/matlabcentral/newsreader/view_thread/314610

[8] another example: https://www.mathworks.com/matlabcentral/newsreader/view_thread/164273

[9] see here: https://stackoverflow.com/questions/3722920/java-how-to-check-current-perm-permgen-size

[10] automatically loaded by Matlab: https://www.mathworks.com/help/matlab/matlab_env/java-opts-file.html

[11] Accessing internal Java class members : https://undocumentedmatlab.com/articles/accessing-internal-java-class-members

[12] Extending a Java class with UDD : https://undocumentedmatlab.com/articles/extending-a-java-class-with-udd

[13] Static Java classpath hacks : https://undocumentedmatlab.com/articles/static-java-classpath-hacks

[14] Matlab callbacks for Java events in R2014a : https://undocumentedmatlab.com/articles/matlab-callbacks-for-java-events-in-r2014a

[15] Matlab callbacks for Java events : https://undocumentedmatlab.com/articles/matlab-callbacks-for-java-events

[16] Creating a simple UDD class : https://undocumentedmatlab.com/articles/creating-a-simple-udd-class

Copyright © Yair Altman - Undocumented Matlab. All rights reserved.