Calling Java Methods from ILE RPG

This section describes how to call Java™ methods from ILE RPG programs.

If the method is not a static method, then it is called an "instance method" and an object instance must be coded as an extra first parameter in order to call the method. For example, if an instance method is prototyped with one parameter, you must call it with two parameters, the first being the instance parameter.

The following steps describe the call from ILE RPG to a Java method:

  1. Java methods can be called using existing operation codes CALLP (when no return value is expected) and EVAL (when a return value is expected). When your RPG procedure attempts to make call to a Java method, RPG will check to see if the Java Virtual Machine (JVM) has been started. If not, RPG will start the JVM for you. It is also possible to start JVM yourself using the JNI function described in Creating the Java Virtual Machine (JVM)
  2. If you are using your own classes (or any classes outside the normal java.xxx classes), be sure to have your CLASSPATH environment variable setup before you call any Java methods. When RPG starts up the JVM for you, it will add the classes in your CLASSPATH environment variable to the standard classpath, so when you use your own classes, Java will be able to find them. Set the CLASSPATH environment variable interactively like this:
    ===>ADDENVVAR ENVVAR(CLASSPATH)
                  VALUE('/myclasses/:/xyzJava/classes/')
    The directories must be separated by colons.
  3. Normally, Java does its own garbage collection, detecting when an object is no longer needed. When you create objects by calling Java constructors from your non-native RPG procedure, Java has no way of knowing that the object can be destroyed, so it never destroys them. You can enable garbage collection for several objects at once by calling the JNI functions described in Telling Java to free several objects at once. If you know you are not going to need an object any more, you should tell this to Java by calling the JNI function described in Telling Java you are finished with a temporary object.
CAUTION:
Since Java uses threads, the THREAD keyword must be coded in all modules that interact with Java. RPG relies heavily on static storage even in subprocedures that apparently only use automatic storage. THREAD keyword is necessary to ensure the correct handling of this static storage. This applies not only to modules that contain calls to Java methods, but also to any modules that might be called during interactions with Java, when the Java part of the application might be running with multiple threads.

See Additional RPG Coding for Using Java for more information about the various JNI functions.

Example 1

In this example, the goal is to add two BigDecimal values together. In order to do this, two BigDecimal objects must be instantiated by calling the constructor for the BigDecimal class, fields must be declared to store the BigDecimal objects, and the add() method in the BigDecimal class must be called.

Figure 79. RPG Code Example Calling BigDecimal Java Class
 *   Prototype the BigDecimal constructor that accepts a String
 *   parameter.  It returns a new BigDecimal object.
 *   Since the string parameter is not changed by the constructor, we will
 *   code the CONST keyword.  This will make it more convenient
 *   to call the constructor.
 *
D bdcreate1       PR              O   EXTPROC(*JAVA:
D                                      'java.math.BigDecimal':
D                                      *CONSTRUCTOR)
D    str                          O   CLASS(*JAVA:'java.lang.String')
D                                     CONST
 *
 *   Prototype the BigDecimal constructor that accepts a double
 *   parameter.  8F maps to the Java double data type and so must
 *   be passed by VALUE.  It returns a BigDecimal object.
 *
D bdcreate2       PR              O   EXTPROC(*JAVA:
D                                      'java.math.BigDecimal':
D                                      *CONSTRUCTOR)
D   double                       8F   VALUE
 *   Define fields to store the BigDecimal objects.
 *
D bdnum1          S               O    CLASS(*JAVA:'java.math.BigDecimal')
D bdnum2          S               O    CLASS(*JAVA:'java.math.BigDecimal')
 *
 *   Since one of the constructors we are using requires a String object,
 *   we will also need to construct one of those.  Prototype the String
 *   constructor that accepts a byte array as a parameter.  It returns
 *   a String object.
 *
D makestring      PR              O    EXTPROC(*JAVA:
D                                       'java.lang.String':
D                                       *CONSTRUCTOR)
D    bytes                      30A    CONST VARYING

 *
 *  Define a field to store the String object.
 *
D string          S               O    CLASS(*JAVA:'java.lang.String')

 *
 *  Prototype the BigDecimal add method.  It accepts a BigDecimal object
 *  as a parameter, and returns a BigDecimal object (the sum of the parameter
 *  and of the BigDecimal object used to make the call).
 *
D add             PR              O    EXTPROC(*JAVA:
D                                       'java.math.BigDecimal':
D                                       'add')
D                                      CLASS(*JAVA:'java.math.BigDecimal')
D   bd1                           O    CLASS(*JAVA:'java.math.BigDecimal') 
D                                      CONST

 *
 *  Define a field to store the sum. *
D sum             S               O    CLASS(*JAVA:'java.math.BigDecimal')
D
D double          S              8F    INZ(1.1)
D fld1            S             10A
 * Define a prototype to retrieve the String version of the BigDecimal
D getBdString     PR              O    CLASS(*JAVA:'java.lang.String')
D                                      EXTPROC(*JAVA:
D                                       'java.lang.BigDecimal':
D                                       'toString')
 * Define a prototype to retrieve the value of a String
D getBytes        PR         65535A    VARYING
D                                      EXTPROC(*JAVA:
D                                       'java.lang.String':
D                                       'getBytes')
 * Define a variable to hold the value of a BigDecimal object
D bdVal           S             63P 5

Here is the code that does the call.

Figure 80.
 *  Call the constructor for the String class, to create a String
 *  object from fld1.  Since we are calling the constructor, we
 *  do not need to pass a String object as the first parameter.
 *
C                   EVAL      string = makestring('123456789012345678901234567890')
 *
 *  Call the BigDecimal constructor that accepts a String
 *  parameter, using the String object we just instantiated.
 *
C                   EVAL      bdnum1 = bdcreate1(string)

 *
 *  Call the BigDecimal constructor that accepts a double
 *  as a parameter.
 *
C                   EVAL      bdnum2 = bdcreate2(double)


 *
 *  Add the two BigDecimal objects together by calling the
 *  add method.  The prototype indicates that add accepts
 *  one parameter, but since add is not a static method, we
 *  must also pass a BigDecimal object in order to make the
 *  call, and it must be passed as the first parameter.
 *  bdnum1 is the object we are using to make the
 *  call, and bdnum2 is the parameter.
 *
C                   EVAL      sum = add(bdnum1:bdnum2)

 *  sum now contains a BigDecimal object with the value
 *  bdnum1 + bdnum2.
C                   EVAL      bdVal = %DECH(getBdString(sum) : 63 : 5)
 * val now contains a value of the sum.  
 * If the value of the sum is larger than the variable "val" can 
 * hold, an overflow exception would occur.

Example 2

This example shows how to perform a TRIM in Java by using the trim() method as an alternative to the ILE RPG %TRIM built-in function. The trim() method in the String class is not a static method, so a String object is needed in order to call it.

Figure 81. RPG Code Example Using trim() Java Method
 *  Define a field to store the String object we wish to trim
 *
D str             S               O   CLASS(*JAVA:'java.lang.String')

D makestring      PR              O   EXTPROC(*JAVA:
D                                      'java.lang.String':
D                                      *CONSTRUCTOR)
D                                     CLASS(*JAVA:'java.lang.String')
D   parm                     65535A   CONST VARYING
 *
 *  Prototype the String method getBytes which converts a String to a byte
 *  array.  We can then store this byte array in an alpha field.
 *  
D getBytes        PR         65535A   EXTPROC(*JAVA:
D                                       'java.lang.String':
D                                       'getBytes') VARYING

 *
 *  Prototype the String method trim.  It doesn't take any parameters,
 *  but since it is not a static method, must be called using a String
 *  object.
 *
D trimstring      PR              O   EXTPROC(*JAVA:
D                                      'java.lang.String':
D                                      'trim')
D fld             S             10A     INZ('   hello    ') VARYING

The call is coded as follows:

Figure 82. RPG Call to the String constructor
 * Call the String constructor
 *
C                   EVAL      str = makestring(fld)

 *
 * Trim the string by calling the String trim() method.
 * We will reuse the str field to store the result.
 *
C                   EVAL      str = trimstring(str)

 * 
 * Convert the string back to a byte array and store it
 * in fld.
 *
C                   EVAL      fld = getBytes(str)

Static methods are called in the same way, except that an object is not required to make a call. If the getBytes() method above was static, the call would look like the example below.


C                        EVAL      fld = getBytes()

If the method does not return a value, use the CALLP operation code.



[ Top of Page | Previous Page | Next Page | Contents | Index ]