Main Content

Pass Arguments To and From Java

Format

When you invoke a method on a generated class, the input arguments received by the method must be in the MATLAB® internal array format. You can either convert them yourself within the calling program, or pass the arguments as Java® data types, which are then automatically converted by the calling mechanism.

To convert them yourself, use instances of the MWArray classes; in this case you are using manual conversion. Storing your data using the classes and data types defined in the Java language means that you are relying on automatic conversion. Most likely, you will use a combination of manual and automatic conversion.

Manual Conversion of Data Types

To manually convert to one of the standard MATLAB data types, use the MWArray data conversion classes provided by the compiler. For class reference and usage information, see the com.mathworks.toolbox.javabuilder package.

Using MWNumericArray

The Magic Square example (Integrate a Java Package into an Application) exemplifies manual conversion. The following code fragment from that program shows a java.lang.Double argument that is converted to an MWNumericArray type that can be used by the MATLAB function without further conversion:

n = new MWNumericArray(Double.valueOf(args[0]),
                                      MWClassID.DOUBLE);

         theMagic = new Class1();

         result = theMagic.makesqr(1, n);

Passing an MWArray.  This example constructs an MWNumericArray of type MWClassID.DOUBLE. The call to myprimes passes the number of outputs, 1, and the MWNumericArray, x:

x = new MWNumericArray(n, MWClassID.DOUBLE);
cls = new myclass();
y = cls.myprimes(1, x);

The Java bridge converts the MWNumericArray object to a MATLAB scalar double to pass to the MATLAB function.

Automatic Conversion to a MATLAB Type

When passing an argument only a small number of times, it is usually just as efficient to pass a primitive Java type or object. In this case, the calling mechanism converts the data for you into an equivalent MATLAB type.

For instance, either of the following Java types would be automatically converted to the MATLAB double type:

  • A Java double primitive

  • An object of class java.lang.Double

For reference information about data conversion (tables showing each Java type along with its converted MATLAB type, and each MATLAB type with its converted Java type), see Rules for Data Conversion Between Java and MATLAB.

Automatic Data Conversion

When calling the makesqr method used in the getmagic application, you could construct an object of type MWNumericArray. Doing so would be an example of manual conversion. Instead, you could rely on automatic conversion, as shown in the following code fragment:

result = M.makesqr(1, arg[0]);

In this case, a Java double is passed as arg[0].

Here is another example:

result = theFourier.plotfft(3, data, new Double(interval));

In this Java statement, the third argument is of type java.lang.Double. According to conversion rules, the java.lang.Double automatically converts to a MATLAB 1-by-1 double array.

Passing a Java Double Object

The example calls the myprimes method with two arguments. The first specifies the number of arguments to return. The second is an object of class java.lang.Double that passes the one data input to myprimes.

cls = new myclass();
y = cls.myprimes(1, new Double((double)n));

This second argument is converted to a MATLAB 1-by-1 double array, as required by the MATLAB function. This is the default conversion rule for java.lang.Double.

Passing an MWArray

This example constructs an MWNumericArray of type MWClassID.DOUBLE. The call to myprimes passes the number of outputs, 1, and the MWNumericArray, x.

x = new MWNumericArray(n, MWClassID.DOUBLE);
cls = new myclass();
y = cls.myprimes(1, x);

The compiler converts the MWNumericArray object to a MATLAB scalar double to pass to the MATLAB function.

Calling MWArray Methods

The conversion rules apply not only when calling your own methods, but also when calling constructors and factory methods belonging to the MWArray classes.

For example, the following code fragment calls the constructor for the MWNumericArray class with a Java double as the input argument:

double Adata = 24;
MWNumericArray A = new MWnumericArray(Adata);
System.out.println("Array A is of type " + A.classID());

The compiler converts the input argument to an instance of MWNumericArray, with a ClassID property of MWClassID.DOUBLE. This MWNumericArray object is the equivalent of a MATLAB 1-by-1 double array.

When you run this example, the result is as follows:

Array A is of type double

Changing the Default by Specifying the Type

When calling an MWArray class method constructor, supplying a specific data type causes the MATLAB Compiler SDK™ product to convert to that type instead of the default.

For example, in the following code fragment, the code specifies that A should be constructed as a MATLAB 1-by-1 16-bit integer array:

double Adata = 24;
MWNumericArray A = new MWnumericArray(Adata, MWClassID.INT16);
System.out.println("Array A is of type " + A.classID());

When you run this example, the result is as follows:

Array A is of type int16

Specify Optional Arguments

So far, the examples have not used MATLAB functions that have varargin or varargout arguments. Consider the following MATLAB function:

function y = mysum(varargin)

y = sum([varargin{:}]);

This function returns the sum of the inputs. The inputs are provided as a varargin argument, which means that the caller can specify any number of inputs to the function. The result is returned as a scalar double.

Pass Variable Numbers of Inputs

The MATLAB Compiler SDK product generates a Java interface to this function as follows:

/* mlx interface - List version*/
public void mysum(List lhs, List rhs)
                          throws MWException
{
   (implementation omitted)
}
/* mlx interface - Array version*/
public void mysum(Object[] lhs, Object[] rhs)
                          throws MWException
{
   (implementation omitted)
}

/* standard interface - no inputs */
public Object[] mysum(int nargout) throws MWException
{
   (implementation omitted)
}

/* standard interface - variable inputs */
public Object[] mysum(int nargout, Object varargin)
                          throws MWException
{
   (implementation omitted)
}

In all cases, the varargin argument is passed as type Object. This lets you provide any number of inputs in the form of an array of Object, that is Object[], and the contents of this array are passed to the compiled MATLAB function in the order in which they appear in the array. Here is an example of how you might use the mysum method in a Java program:

public double getsum(double[] vals) throws MWException
{
   myclass cls = null;
   Object[] x = {vals};
   Object[] y = null;

   try
   {
      cls = new myclass();
      y = cls.mysum(1, x);
      return ((MWNumericArray)y[0]).getDouble(1);
   }

   finally
   {
      MWArray.disposeArray(y);
      if (cls != null)
	      cls.dispose();
   }
}

In this example, an Object array of length 1 is created and initialized with a reference to the supplied double array. This argument is passed to the mysum method. The result is known to be a scalar double, so the code returns this double value with the statement:

return ((MWNumericArray)y[0]).getDouble(1);

Cast the return value to MWNumericArray and invoke the getDouble(int) method to return the first element in the array as a primitive double value.

Pass Array Inputs.  The next example performs a more general calculation:

public double getsum(Object[] vals) throws MWException
{
   myclass cls = null;
   Object[] x = null;
   Object[] y = null;

   try
   {
      x = new Object[vals.length];
      for (int i = 0; i < vals.length; i++)
         x[i] = new MWNumericArray(vals[i], MWClassID.DOUBLE);

      cls = new myclass();
      y = cls.mysum(1, x);
      return ((MWNumericArray)y[0]).getDouble(1);
   }
   finally
   {
      MWArray.disposeArray(x);
      MWArray.disposeArray(y);
      if (cls != null)
         cls.dispose();
   }
}

This version of getsum takes an array of Object as input and converts each value to a double array. The list of double arrays is then passed to the mysum function, where it calculates the total sum of each input array.

Pass a Variable Number of Outputs

When present, varargout arguments are handled in the same way that varargin arguments are handled. Consider the following MATLAB function:

function varargout = randvectors

for i=1:nargout
   varargout{i} = rand(1, i);
end

This function returns a list of random double vectors such that the length of the ith vector is equal to i. The MATLAB Compiler™ product generates a Java interface to this function as follows:

/* mlx interface - List version */
 public void randvectors(List lhs, List rhs) throws MWException
{
   (implementation omitted)
}
/* mlx interface - Array version */
public void randvectors(Object[] lhs, 
           Object[] rhs) throws MWException
{
   (implementation omitted)
}
/* Standard interface - no inputs*/
public Object[] randvectors(int nargout) throws MWException
{
   (implementation omitted)
}

Pass Optional Arguments with the Standard Interface.  Here is one way to use the randvectors method in a Java program:

public double[][] getrandvectors(int n) throws MWException
{
   myclass cls = null;
   Object[] y = null;

   try
   {
      cls = new myclass();
      y = cls.randvectors(n);
      double[][] ret = new double[y.length][];

      for (int i = 0; i < y.length; i++)
         ret[i] = (double[])((MWArray)y[i]).getData();
      return ret;
   }

   finally
   {
      MWArray.disposeArray(y);
      if (cls != null)
         cls.dispose();
   }
}

The getrandvectors method returns a two-dimensional double array with a triangular structure. The length of the ith row equals i. Such arrays are commonly referred to as jagged arrays. Jagged arrays are easily supported in Java because a Java matrix is just an array of arrays.

Handle Return Values

The previous examples used the fact that you knew the type and dimensionality of the output argument. In the case that this information is unknown, or can vary (as is possible in MATLAB programming), the code that calls the method might need to query the type and dimensionality of the output arguments.

There are several ways to do this. Do one of the following:

  • Use reflection support in the Java language to query any object for its type.

  • Use several methods provided by the MWArray class to query information about the underlying MATLAB array.

  • Coercing to a specific type using the toTypeArray methods.

Use Java Reflection to Determine Type and Dimensionality

This code sample calls the myprimes method, and then determines the type using reflection. The example assumes that the output is returned as a numeric matrix but the exact numeric type is unknown.

public void getprimes(int n) throws MWException
{
   myclass cls = null;
   Object[] y = null;

   try
   {
      cls = new myclass();
      y = cls.myprimes(1, new Double((double)n));
      Object a = ((MWArray)y[0]).toArray();

      if (a instanceof double[][])
      {
         double[][] x = (double[][])a;

         /* (do something with x...) */
      }

      else if (a instanceof float[][])
      {
         float[][] x = (float[][])a;

         /* (do something with x...) */
      }

      else if (a instanceof int[][])
      {
         int[][] x = (int[][])a;

         /* (do something with x...) */
      }

      else if (a instanceof long[][])
      {
         long[][] x = (long[][])a;

         /* (do something with x...) */
      }

      else if (a instanceof short[][])
      {
         short[][] x = (short[][])a;

         /* (do something with x...) */
      }

      else if (a instanceof byte[][])
      {
         byte[][] x = (byte[][])a;

         /* (do something with x...) */
      }

      else
      {
         throw new MWException(
            "Bad type returned from myprimes");
      }
   }

This example uses the toArray method to return a Java primitive array representing the underlying MATLAB array. The toArray method works just like getData in the previous examples, except that the returned array has the same dimensionality as the underlying MATLAB array.

Use MWArray Query to Determine Type and Dimensionality

The next example uses the MWArray classID method to determine the type of the underlying MATLAB array. It also checks the dimensionality by calling numberOfDimensions. If any unexpected information is returned, an exception is thrown. It then checks the MWClassID and processes the array accordingly.

public void getprimes(int n) throws MWException
{
   myclass cls = null;
   Object[] y = null;

   try
   {
      cls = new myclass();
      y = cls.myprimes(1, new Double((double)n));
      MWClassID clsid = ((MWArray)y[0]).classID();

      if (!clsid.isNumeric() ||
         ((MWArray)y[0]).numberOfDimensions() != 2)
      {
         throw new MWException("Bad type 
                          returned from myprimes");
      }

      if (clsid == MWClassID.DOUBLE)
      {
         double[][] x = (double[][])((MWArray)y[0]).toArray();

         /* (do something with x...) */
      }

      else if (clsid == MWClassID.SINGLE)
      {
         float[][] x = (float[][])((MWArray)y[0]).toArray();

         /* (do something with x...) */
      }

      else if (clsid == MWClassID.INT32 || 
              clsid == MWClassID.UINT32)
      {
         int[][] x = (int[][])((MWArray)y[0]).toArray();

         /* (do something with x...) */
      }

      else if (clsid == MWClassID.INT64 || 
              clsid == MWClassID.UINT64)
      {
         long[][] x = (long[][])((MWArray)y[0]).toArray();

         /* (do something with x...) */
      }

      else if (clsid == MWClassID.INT16 || 
              clsid == MWClassID.UINT16)
      {
         short[][] x = (short[][])((MWArray)y[0]).toArray();

         /* (do something with x...) */
      }

      else if (clsid == MWClassID.INT8 || 
              clsid == MWClassID.UINT8)
      {
         byte[][] x = (byte[][])((MWArray)y[0]).toArray();

         /* (do something with x...) */
      }
   }
   finally
   {
      MWArray.disposeArray(y);
      if (cls != null)
         cls.dispose();
   }
}

Use toTypeArray Methods to Determine Type and Dimensionality

The next example demonstrates how you can coerce or force data to a specified numeric type by invoking any of the toTypeArray methods. These methods return an array of Java elements of the type specified in the name of the called method. The data is coerced or forced to the primitive type specified in the method name. Note that when using these methods, data will be truncated when needed to allow conformance to the specified data type.

Object results = null;
try {
    // call a compiled MATLAB function
    results = myobject.myfunction(2);

    // first output is known to be a numeric matrix
    MWArray resultA = (MWNumericArray) results[0];
   double[][] a = (double[][]) resultA.toDoubleArray();

    // second output is known to be 
    //    a 3-dimensional numeric array
    MWArray resultB = (MWNumericArray) results[1];
   int[][][] b = (int[][][]) resultB.toIntArray();   
}
 finally {
    MWArray.disposeArray(results);
}