Calling Java from MATLAB with pass-by-reference arrays

MATLAB has a pretty intimate connection with Java, supporting the creation and manipulation of native Java objects directly in MATLAB source code. For example:

x = java.lang.Double(pi);

Contrast this with C++, where it is typically necessary to write an additional small amount of “wrapper” C code using the MEX API to bridge the gap between languages.

For the most part, conversions between MATLAB and Java data types are automatic, as expected, and as desired… with one exception: passing a primitive array by reference. For example, suppose that we want to call a static method in a third-party Java library that converts an input 6-state vector (as a primitive array of 6 doubles) from one coordinate frame to another, by populating a given “output” array of 6 doubles:

public static int convert(double[] x_in, double[] x_out) { ... }

As far as I can tell, it is impossible to use a method like this directly from MATLAB. The problem is that we can never construct the necessary output buffer x_out, and hold onto it as a reference that could be passed to convert. MATLAB insists on automatically converting any such reference to a Java array of primitive type into its “value” as a MATLAB array of the corresponding native type, leaving the reference to the actual “buffer” behind in the Java address space.

Interestingly, MATLAB’s built-in function javaArray seems like it might have been intended for situations like this. But the arrays created by this built-in function are not of the necessary primitive data types, but of their “boxed” counterparts, which seems almost entirely useless to me, since I don’t know of any Java libraries whose interface involves arrays of boxed primitive types.

So, it seems that we need at least some additional wrapper Java code to make methods like this usefully accessible from MATLAB. The objective of this post is to provide an implementation that I think fills this gap in a reasonably general way, by using Java’s reflection mechanism to allow creating primitive arrays and passing them by reference to any Java method directly from MATLAB.

(Aside: I suppose I get some masochistic enjoyment from repeatedly using the phrase “pass by reference” here, hoping for pedantic complaints arguing that “Java is pass by value, not pass by reference.”)

The code is available on GitHub, as well as the old location here. Following is a simple example showing how it works:

s = java.lang.String('foo');
dst = matlab.JavaArray('java.lang.Character', 3);
callJava('getChars', s, int32(0), int32(3), dst, int32(0));

The idea is similar to the libpointer and calllib interface to C shared libraries: a matlab.JavaArray acts like a libpointer, and callJava acts like calllib, automatically “unwrapping” any matlab.JavaArray arguments into their underlying primitive array references.

Finally, a disclaimer: the method dispatch is perhaps overly simple, keying only on the desired method name and provided number of arguments. If your Java class has multiple methods with the same name, and the same number of parameters– regardless of their type, or of the return type– the first method matching these two criteria will be called.

This entry was posted in Uncategorized. Bookmark the permalink.

6 Responses to Calling Java from MATLAB with pass-by-reference arrays

  1. hoping for pedantic complaints arguing that “Java is pass by value, not pass by reference

    You beat me to it!

    • Yeah; I never understood the arguments about this. In C++ it makes sense to distinguish between “pass by pointer” and “pass by reference,” but there is no useful distinction in Java (even the language specification uses the term).

  2. wilmington says:

    Suppose you change the signature of the function that you are calling to:

    public static double [] convert(double[] x_in) { … }

    ignoring the status return code for now. That is, the output comes back as the return value of the Java function. Would this then be directly callable from MATLAB?

    • Correct, this would work fine directly from MATLAB. In my case, the function is provided as part of a third-party library, so I can’t change the signature. Worse, it’s not just one function like this, but dozens with similar “input-arrays-to-be-populated-with-output” signatures.

  3. Benjamin Davis says:

    It is good to see that someone else discovered this workaround based on reflection API. There was no mention of it in the MATLAB Central, similar questions there have been answered by MATLAB engineers as “it is not possible”.

    I also discovered this solution independently and created an FEX submission to allow easy use. I wish I would have read your post first, it would have been much easier.

    The major difference between our implementations is that mine is pure MATLAB, and one has to pass the signature of the function explicitly (e.g. ‘read(byte[],int,int)’).

    I will go back to MATLAB Central and update the thread there so it links to your answer as well. This workaround should be more widely publicized.

    • Very interesting, thanks for the link to a very clear write-up of details of the problem and your solution. I think we even encountered the same motivating example– over a decade ago I needed to read from a Java TCP socket, and couldn’t figure out how to do it without resorting to specific additional Java wrapper code.

      (However, at least for that very specific instance of this problem, there is now a “native” MATLAB way to read from an InputStream– that didn’t exist at the time– with the introduction of the Java Channels API. You can wrap an InputStream in a java.nio.channels.Channels.newChannel(), then read into a java.nio.ByteBuffer.allocate(numBytes).)

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.