Java access functions

The Java™ access functions are EGL system functions that you use to access local Java objects and classes through your Java code. Specifically, these functions access the public methods, constructors, and fields of the local code. These are older functions that EGL maintains for compatibility with earlier versions. For new code, use the more powerful ExternalType syntax; for more information, see ExternalType part.

This EGL feature is made possible at run time by the presence of the EGL Java object space, which is a set of names and the objects to which those names refer. A single object space is available to your generated program and to all generated Java code that your program calls locally, whether the calls are direct or by way of another local generated Java program, to any level of call. The object space is not available in any local Java code.

To store and retrieve objects in the object space, invoke the Java access functions. Your invocations can include identifiers, each of which is a string that is used to store an object or to match a name that already exists in the object space. When an identifier matches a name, your code can access the object associated with the name.

Each of the arguments you pass to a method (and each value that you assign to a field) is mapped to a Java object or primitive type; for more, see Passing arguments to Java types.

EGL code that includes a Java access function cannot be generated as a COBOL program.

Examples

This section gives examples on how to use Java access functions.

Testing a system property

The following example retrieves a system property and tests for the absence of a value:
  // assign the name of an identifier to a variable of type CHAR
  valueID = "osNameProperty"

  // place the value of property os.name into the 
  // object space, and relate that value (a Java String) 
  // to the identifier osNameProperty
  javaLib.store(valueId as "objID:java", "java.lang.System",
    "getProperty", "os.name");

  // test whether the property value is non-existent
  // and process accordingly
  myNullFlag = javaLib.isNull( valueId as "objID:java" );
  
  if( myNullFlag == 1 )
    error = 27;
  end 

Working with arrays

When you work with Java arrays in EGL, use the java.lang.reflect.Array Java class, as described in the Java API documentation. You cannot use javaLib.storeNew() to create a Java array because Java arrays have no constructors.

Use the static method newInstance() of java.lang.reflect.Array to create the array in the object space. After you create the array, use other methods in that class to access the elements.

The newInstance() method expects two arguments:
  • A Class object that determines the type of array being created
  • A number that specifies how many elements are in the array

The code that identifies the Class object varies depending on whether you are creating an array of objects or an array of primitives. The examples in the following sections show this variation.

Working with an array of objects

The following example shows how to create a 5-element object array that is accessible by use of the identifier "myArray":
  // Get a reference to the class, for use with newInstance()
  javaLib.store( "objectClass" as "objID:java", "java.lang.Class",
    "forName", "java.lang.Object" );

  // Create the array in the object space
  javaLib.store( "myArray" as "objID:java", "java.lang.reflect.Array",
    "newInstance", "objectClass" as "objID:java", 5 );

To create an array that holds a different type of object, change the class name that is passed to the first invocation of javaLib.store(). To create an array of String objects, for example, pass java.lang.String instead of java.lang.Object.

To access an element of an object array, use the get and set methods of java.lang.reflect.Array. In the following example, i and length are numeric variables:
  length = javaLib.invoke( "java.lang.reflect.Array", 
    "getLength", "myArray" as "objID:java" );
  i = 0; 

  while ( i < length ) 
    javaLib.store( "element" as "objID:java", "java.lang.reflect.Array",
      "get", "myArray" as "objID:java", i );

    // Here, process the element as appropriate
    javaLib.invoke( "java.lang.reflect.Array", "set", 
      "myArray" as "objID:java", i, "element" as "objID:java" ); 
    i = i + 1; 
  end  
The previous example is equivalent to the following Java code:
  int length = myArray.length; 
  
  for ( int i = 0; i < length; i++ ) 
  { 
    Object element = myArray[i]; 

    // Here, process the element as appropriate

    myArray[i] = element; 
  }  

Working with an array of Java primitives

To create an array that stores a Java primitive rather than an object, use a different mechanism in the steps that precede the use of java.lang.reflect.Array. In particular, obtain the Class argument to newInstance() by accessing the static field TYPE of a primitive type class.

The following example creates myArray2 (a 30-element array of integers):
  // Get a reference to the class, for use with newInstance
  javaLib.storeField( "intClass" as "objID:java", 
    "java.lang.Integer", "TYPE");

  // Create the array in the object space
  javaLib.store( "myArray2" as "objID:java", "java.lang.reflect.Array",
    "newInstance", "intClass"  as "objID:java", 30 );  

To create an array that holds a different type of primitive, change the Class name that is passed to the invocation of javaLib.storeField(). To create an array of characters, for example, pass java.lang.Character instead of java.lang.Integer.

To access an element of an array of primitives, use the java.lang.reflect.Array methods that are specific to a primitive type. Such methods include getInt(), setInt(), getFloat(), setFloat(), and so forth. In the following example, length, element, and i are numeric variables:
  length = javaLib.invoke( "java.lang.reflect.Array", 
    "getLength", "myArray2" as "objID:java" ); 
  i = 0; 

  while ( i < length )
    element = javaLib.invoke( "java.lang.reflect.Array", 
      "getDouble", "myArray2" as "objID:java", i ); 

    // Here, process an element as appropriate

    javaLib.invoke( "java.lang.reflect.Array", "setDouble",
      "myArray2" as "objID:java", i, element );
    i = i + 1; 
  end
The previous example is equivalent to the following Java code:
  int length = myArray2.length;

  for ( int i = 0; i < length; i++ )
  { 
    double element = myArray2[i];

    // Here, process an element as appropriate

    myArray2[i] = element;
  }  

Working with collections

To iterate over a collection that is referenced by a variable named list, a Java program runs the following code:
  Iterator contents = list.iterator(); 

  while( contents.hasNext() ) 
  { 
    Object myObject = contents.next();
    // Process myObject
  }
Assume that hasNext is a BOOLEAN variable and that your program related a collection to an identifier named list. The following EGL code is then equivalent to the Java code above:
  javaLib.store( "contents" as "objID:java", 
                 "list" as "objID:java", "iterator" );
  hasNext = javaLib.invoke( "contents"  as "objID:java", "hasNext" ); 

  while ( hasNext ) 
    javaLib.store( "myObject" as "objID:java", 
                   "contents" as "objID:java", "next");

    // Process myObject
    hasNext = javaLib.invoke( "contents" as "objID:java", "hasNext" );
  end

Converting an array to a collection

To create a collection from an array of objects, use the asList() method of java.util.Arrays, as shown in the following example:
  // Create a collection from array myArray 
  // and relate that collection to the identifier "list 
  javaLib.store( "list" as "objID:java", "java.util.Arrays",
                 "asList", "myArray" as "objID:java" );

Next, iterate over the list, as shown in the preceding section.

The transfer of an array to a collection works only with an array of objects, not with an array of Java primitives. Be careful not to confuse java.util.Arrays with java.lang.reflect.Array.

Error handling

If you use default error handling (v60ExceptionCompatibility set to NO) and the invoked Java code throws an exception, EGL responds by throwing a JavaObjectException. Errors on the EGL side cause a RuntimeException. Also see the "Error considerations" for each individual function.

If you use V6 exception compatibility (see Using V6 exception compatibility), you can access the values in sysVar.errorCode set by functions in javaLib (described in the individual topics for those functions).

Of particular interest is the sysVar.errorCode value "00001000", which indicates that an exception was thrown by an invoked method or as a result of a class initialization.

When an exception is thrown, EGL stores it in the object space. If another exception occurs, the second exception takes the place of the first. You can use the identifier caughtException to access the latest exception that occurred.

In an unusual situation, an invoked method throws an error instead of an exception, such as OutOfMemoryError or StackOverflowError. In such cases, the program ends regardless of the value of the vgVar.handlesysLibraryErrors system variable.

The following Java code shows how a Java program can have multiple catch blocks to handle different kinds of exceptions. This code tries to create a FileOutputStream object. A failure causes the code to set an errorType variable and to store the exception that was thrown.
  int errorType = 0;
  Exception ex = null;
  
  try
  {
    java.io.FileOutputStream fOut = 
      new java.io.FileOutputStream( "out.txt" );
  }
  catch ( java.io.IOException iox )
  {
    errorType = 1;
    ex = iox;
  }
  catch ( java.lang.SecurityException sx )
  {
    errorType = 2;
    ex = sx;
  } 
The following EGL code is equivalent to the previous Java code:
  vgVar.handlesysLibraryErrors = 1;
  errorType = 0;
  
  javaLib.storeNew( "fOut" as "objID:java",
                    "java.io.FileOutputStream", "out.txt" );

  if ( sysVar.errorCode == "00001000" )
    case ( javaLib.qualifiedTypeName( "caughtException" as "objID:java" ) )

      when ( "java.io.IOException" )
        errorType = 1;
        javaLib.storeCopy( "caughtException" as "objID:java", 
                           "ex" as "objID:java" );
      when ( "java.lang.SecurityException" )
        errorType = 2;
        javaLib.storeCopy( "caughtException" as "objID:java",
                           "ex" as "objID:java" );
    end
  end

Feedback