IBM Support

Troubleshoot calls from RPG to Java

General Page

You are in: RPG Cafe > Troubleshoot calls to Java

Short URL: http://ibm.biz/troubleshoot_rpg_calls_to_java

RPG Cafe: Troubleshoot calls to Java

Troubleshoot problems with calling Java™ methods from RPG

.                                            .
.                                            .

The call to a Java method is failing with RNX0301

.                                            .
.                                            .

The Java method failed with a Java exception

To see the Java exception causing the error, inspect the RNX0301 message that you received. The Java exception is listed in the help for the message.

If the Java exception is one of these messages, check that section of this document first: NoClassDefFound, or NoSuchMethodError.

If you want to see exactly which Java class threw the exception, see the section on getting an exception trace from Java.

If you think the exception should not be occurring, check whether one of the following problems could be causing the error:

.                                            .
.                                            .

My Java class works fine when called from Java, but doesn't work when called from RPG.

The most common cause of this problem is that the JVM is running under a different Java version when you call the Java method from your RPG program. See the section on setting the Java version.

.                                            .
.                                            .

The application runs fine and then suddenly starts failing.

When you create Java objects from your RPG programs, or when you call Java methods that return Java objects, the JVM keeps track of the fact that you have references to those objects. Until you tell the JVM that you don't need those objects any more, the objects cannot be freed during garbage collection. Eventually, no more objects can be created.

Ensure you are freeing objects when you no longer need them. See the section on freeing objects.

There might be a Java system property that controls the number of objects that can be created. Check the list of the available Java system properties in the Java section of the IBM Knowledge Center. https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/rzaha/sysprop2.htm

.                                            .
.                                            .

How can I set the Java version?

If you are using the Classic JVM, available before 7.1, the Java version is set by the java.version system property. See the section on setting Java properties.

If you are using "IBM Technology for Java", the Java version is set by using the JAVA_HOME environment variable: https://www.ibm.com/support/knowledgecenter/ssw_ibm_i_74/rzaha/runfirst.htm.

  • In 6.1, setting the java.version property causes Java to use the Classic JVM. If you do not set the java.version property, Java uses the "IBM Technology for Java" JVM.
  • In 7.1, the Classic JVM is not available, so the java.version property is ignored.
.                                            .
.                                            .

Why does Java seem to ignore my CLASSPATH or QIBM_RPG_JAVA_PROPERTIES environment variables?

  • The environment variables are only used when the RPG run time is starting the JVM. If the JVM is already started, the environment variables are ignored. The JVM might already be started by some other RPG program making a Java method call, or by some explicit JNI coding to start the JVM.

    Tip: If you have several different RPG applications that all need to call Java methods, set up LEVEL(*SYS) environment variables for CLASSPATH and QIBM_RPG_JAVA_PROPERTIES; the classpath must include all the classes that might be need by any application. With a LEVEL(*SYS) environment variable, every job starts with that environment variable already set.

  • The environment variables are case-sensitive. For example, an environment variable named "classpath" or "qibm_rpg_java_properties" would not be found.
  • If the properties are not specified correctly, they are ignored. See the section on Java properties.
.                                            .
.                                            .

How do I free my Java objects?

See the Java section in the ILE RPG Programmer's Guide information on how to free Java objects. You can free them one at a time, or free several objects at once.

If you are already freeing your objects, you might need to free them more often. For example, if you free all your objects at the end of your program, but within your program you create several objects for each record of a file, then consider freeing objects after the processing for each record, rather than waiting until the end of the program.

.                                            .
.                                            .

How can I get an exception trace from Java?

See the ILE RPG Programmer's Guide on how to use the QIBM_RPG_EXCP_TRACE environment variable.

Unlike other environment variables associated with Java, the QIBM_RPG_EXCP_TRACE environment variable can be set and unset at any time. It is checked whenever a Java method call from RPG ends with an exception.

.                                            .
.                                            .

How can I see the System.out and System.err output?

  • When you run your program in batch, you get a QPRINT file containing the Java output.
  • When you run your program from QSH, you get the output to the QSH screen. To run your program from QSH, call it like this:
            ===> /qsys.lib/mylib.lib/mypgm.pgm
          

    Warning: When you call your program this way, be aware that the parameters are passed as null-terminated strings. In general, this way is only convenient if you have no parameters, since you would have to have different processing in your program for your parameters, depending on whether you were called from the command line or from QSH.

  • Otherwise, you must do a few things to get the output. Note that the environment variables must be set before the JVM is started, and the file descriptors must be opened before any Java output is done:
    1. Set the Java property os400.stdout=file:path and os400.stderr=filepath, specifying the locations where you want the output to go. For example, if you use QIBM_RPG_JAVA_PROPERTIES to set the Java properties, and you want the output to go to files /mydir/out.txt and /mydir/err.txt, you would specify
                    ===> ADDENVVAR QIBM_RPG_JAVA_PROPERTIES
                            VALUE('-Dos400.stdout=file:/mydir/out.txt;-Dos400.stderr=file:/mydir.err.txt;')
                 
    2. Set the environment variable QIBM_USE_DESCRIPTOR_STDIO to the value 'Y'.
    3. Check that the three standard-I/O file descriptors are open. Create the CHECKSTDIO program and call it before you call your RPG application, or you could call it from your RPG application.
.                                            .
.                                            .

How do I set the class path?

The class path can be set by the CLASSPATH environment variable, or by the java.class.path property. The class path consists of directories and JAR files. The entries are separated by a colon.

For example, if you have .class objects in directory /mydir/myclasses and you also have JAR files /sysclasses/app1.jar and /myclasses/myjar.jar, then your classpath would look like this:

      /myclasses:/sysclasses/app1.jar:/myclassses/myjar.jar
   

If you have a directory containing JAR files, it is not sufficient to just specify the directory. You must explicitly specify each JAR file.

      /myjars/jar1.jar:/myjars/jar2.jar:/myjars/jar3.jar
   

Also, see the section Why does Java seem to ignore my CLASSPATH or QIBM_RPG_JAVA_PROPERTIES environment variables.

.                                            .
.                                            .

How do I set Java properties?

You can set Java properties by using the SystemDefault.properties file. There are several different places you can store this file. See the Java documentation in the IBM Knowledge Center for more information.

You can set Java properties by using the QIBM_RPG_JAVA_PROPERTIES environment variable.

When you use both the SystemDefault.properties file and the QIBM_RPG_JAVA_PROPERTIES environment variable, the properties specified by the environment variable override the properties specified by the file.

Note: The Java properties are case-sensitive. For example, setting the OS400.RUN.VERBOSE property has no effect; you must set the os400.run.verbose property.

Notes:

  • In 6.1, setting the java.version property causes Java to use the Classic JVM. When you do not set the java.version property, Java uses the "IBM Technology for Java" JVM.
  • Starting in 7.1, the java.version property is ignored. Only the "IBM Technology for Java" JVM is available.
.                                            .
.                                            .

How do I use the QIBM_RPG_JAVA_PROPERTIES environment variable?

The environment variable must be set before the JVM is created. The JVM is created when the first RPG program in the job calls a Java method. Any further changes to the environment variable are ignored in that job.

The properties are specified the same as for the QSH java command, in the form "-Dproperty=value".

The properties are case-sensitive; "os400.run.verbose" is not the same as "OS400.RUN.VERBOSE".

The value of the environment variable is in the form "property;property;property;" where each property is terminated by a semicolon. (It is not strictly necessary to use a semicolon; other characters could be used if they are all the same, and if they are not used anywhere else in the actual properties.)

Examples:

  • Set the os400.stdout property to myfile.txt
    ADDENVVAR QIBM_RPG_JAVA_PROPERTIES VALUE('-Dos400.stdout=file:myfile.txt;')
  • Set the os400.run.verbose property to true
    ADDENVVAR QIBM_RPG_JAVA_PROPERTIES VALUE('-Dos400.run.verbose=true;')
  • Set the os400.run.verbose and os400.stdout properties
    ADDENVVAR QIBM_RPG_JAVA_PROPERTIES VALUE('-Dos400.run.verbose=true;-Dos400.stdout=file:myfile.txt;')
  • Same as the previous example, but use a different terminator character, '!'
    ADDENVVAR QIBM_RPG_JAVA_PROPERTIES VALUE('-Dos400.run.verbose=true!-Dos400.stdout=file:myfile.txt!')

For more information, see the ILE RPG Programmer's Guide.

.                                            .
.                                            .

How can I find out what Java version and classpath are being used in the JVM?

On 7.1, or if you are not using a Classic JVM

Use the WRKJVMJOB command.

Before 7.1, if you are using a Classic JVM

You can use the DMPJVM command to get information on the version and classpath and many other things. The JVM must already be started before DMPJVM is done.

Also, the DMPJVM command must be issued from a different job. An easy way to do that is to submit the DMPJVM command for your current job. For example, if your current job is QPADEV0002 JSMITH 023816, then you could do the following command, and then inspect the spooled output.

      ===> DMPJVM JOB(023816/JSMITH/QPADEV0002)
   

You can also retrieve any system property by calling the getProperty method in the System class. See the source below, for a program that interactively displays properties.

.                                            .
.                                            .

Determine exactly which Java classes are being used at run time

Specify the os400.run.verbose=true Java property.

See the section on setting Java properties for more information.

If the output flashes on the screen too fast for you to see it, or does not appear at all, see the section on seeing the System.out and System.err output.

.                                            .
.                                            .

Changing Java classes after the JVM has been started

If the JVM is already created in your job, and you then change a Java class, or create a new Java class, the changes are not recognized by Java in that job. You must sign off and sign back on again to have Java "see" your changes.

While you are developing Java classes for use by RPG, it is sometimes more convenient to submit your tests to batch rather than continually sign off and back on. If you use SBMJOB for your tests, be sure to ask for your current environment variables to be used for the submitted job:

   ===> SBMJOB CPYENVVAR(*YES)
   

Note: It is not necessary to start a new job when you only change your RPG programs.

.                                            .
.                                            .

The Java exception is NoClassDefFound

If the class mentioned in the Java exception is not the same as the class of the method being called, it is likely that the called Java method received this exception. See the section on failed Java method calls.

The call could not complete because Java could not find the class specified by the RPG prototype for the Java call. Check the following. If you find any problems, correct them and try again.

  • The Java method is spelled correctly in the EXTPROC keyword for the Java method, and with the correct case. (MYCLASS and myclass are not considered the same by Java.)
  • The class is in a JAR file, but the JAR file is not mentioned in the classpath. See the section on setting the classpath.
  • The class is new on the system, and the JVM was previously started in the job (probably by other calls from RPG to Java). See the section on changing Java classes after the JVM has been started.
.                                            .
.                                            .

The Java exception is NoSuchMethodError

Note: If the class mentioned in the Java exception is not the same as the class of the method being called, it is likely that the called Java method received this exception. See the section on failed Java method calls.

If the class mentioned in the Java exception is the same as the class of the method being called, then the reason for the failed call is that Java did not find the method specified by the RPG prototype for the Java call.

Check the following:

  • The EXTPROC for the Java method has the Java class and method name spelled correctly, and with the correct case (MYCLASS and myclass are not considered the same by Java).
  • The Java method has the static keyword, but the STATIC keyword was not specified for the RPG prototype.
  • The Java method has no return type, and the name of the method is the same as the name of the class. If so, then the Java method is a constructor, and the special method "name" of *CONSTRUCTOR must be used for the RPG prototype. Read the section in the ILE RPG Programmer's Guide on how to code the RPG prototype for a Java constructor.
  • The signature does not match the actual Java class. If so, read the section in the ILE RPG Programmer's Guide on how to code the RPG prototype for a Java method. To see the expected signature for the Java method, use the javap command; there is an example in the help for the RNX0301 message.
  • The method is new in the class, or the signature (return type and parameters) changed, and the JVM was previously started in the job (probably by other calls from RPG to Java). See the section on changing Java classes after the JVM has been started.
  • The Java method requires a particular Java version. If so, see the sections on finding out what Java version is being used in the JVM and setting the Java version.
.                                            .
.                                            .

Source code for program CHECKSTDIO

This program can be used as part of the setup necessary to see the Java output from an interactive job. See the section on How can I see the System.out and System.err output? for the other setup that is required.

This program must be called when the job starts to ensure that the three "Standard I/O" descriptors 0, 1, and 2 are opened.

See attachment 1 for the source code.

.                                            .
.                                            .

Source code for program JAVAPROP

This program can be used for casual inspection of the Java properties in effect. Use the DMPJVM command when you want full information about the JVM.

Warnings:

  1. Running this program starts the JVM if it has not already started. If you have some special code that runs before the JVM is started (for example, to set up environment variables) be sure to do that first.
  2. This program assumes that you have a binding directory called JNIUTIL containing the procedures getJniEnv, beginObjGroup and endObjGroup, and that the prototypes for these procedures are in a source file *LIBL/QRPGLESRC(JNIUTIL). You can find the source code for these procedures in the ILE RPG Programmer's Guide.

    If you aren't sure what the property names are, you could use the ALLJVAPROP program. See its source in attachment 2 below.

.                                            .
.                                            .

Source code for program ALLJVAPROP

This program can be used to see all the possible Java properties you could set. Note that the warnings listed for the JAVAPROP program also apply to this program.

See attachment 3.

.                                            .
.                                            .

Details of changes to this document

  • Version 4, 2019-11-30
    • Removed information about running on releases before V5R3.
  • Version 3, 2013-03-26
    • Updated information about the java.version property for 6.1 and 7.1.
    • Updated information about how to get information about the JVM for J9.
  • Version 2, 2010-06-02
    • The recommended ALLOCSTDIO program was flawed in that it just opened three random descriptors, and it allowed them to be closed again.

      It was replaced by the CHECKSTDIO program which first checks whether descriptors 0, 1, and 2 are already open, and it checks whether they are correctly opened for input (0) or output (1 and 2).

      The CHECKSTDIO program does not provide any way of closing the descriptors later.

Attachments

  1. CHECKSTDIO source: CHECKSTDIO.rpgle_.txt
  2. JAVAPROP source: JAVAPROP.rpgle_.txt
  3. ALLJVAPROP source: ALLJVAPROP.rpgle_.txt

[{"Business Unit":{"code":"BU054","label":"Systems w\/TPS"},"Product":{"code":"SS69QP","label":"Rational Development Studio for i"},"Component":"ILE RPG Compiler","Platform":[{"code":"PF012","label":"IBM i"}],"Version":"All Versions","Edition":"","Line of Business":{"code":"LOB08","label":"Cognitive Systems"}}]

Document Information

Modified date:
19 December 2019

UID

ibm11117695