Skip to main content
Previous section

Mapping Specification

This chapter describes the mapping between Java objects and the InterSystems IRIS® proxy classes that represent the Java objects.

Important:

Only classes, methods, and fields marked as public are imported.

This chapter describes mappings of the following types:

Package and Class Names

Package and class names are preserved when imported, except that each underscore (_) in an original Java class name is replaced with the character u and each dollar sign ($) is replaced with the character d in the InterSystems IRIS proxy class name. Both the u and the d are case-sensitive (lowercase).

Primitives

Primitive types and primitive wrappers map from Java to InterSystems IRIS as shown in the following table.

Java InterSystems IRIS
boolean %Library.Boolean
byte %Library.Integer
char %Library.String
double %Library.Numeric
float %Library.Double
int %Library.Integer
long %Library.Integer
short %Library.SmallInt
java.lang.Boolean %Library.Boolean
java.lang.Double %Library.Numeric
java.lang.Float %Library.Double
java.lang.Integer %Library.Integer
java.lang.Long %Library.Integer
java.lang.Short %Library.SmallInt
java.lang.String %Library.String

Primitive Java type wrappers are mapped by default to their corresponding InterSystems IRIS data types for performance reasons. It is recommended that you always use data types whenever you are passing an argument whose type is a primitive wrapper. For example, you can call the following Java method:

public Long getOrderNumber(Integer id, Float rate)
Copy code to clipboard

as follows in InterSystems IRIS:

 Set id=5
 Set rate=10.0
 // order is a local variable
 Set order=test.getOrderNumber(id,rate)
Copy code to clipboard

However, you are also free to import primitive wrapper types as is, then use them that way from your InterSystems IRIS code, for example:

 Set id=##class(java.lang.Integer).%New(gateway,5)
 Set rate=##class(java.lang.Float).%New(gateway,10.0)
 // order is of java.lang.Long type
 Set order=test.getOrderNumber(id,rate)
Copy code to clipboard

Date and Time

Date and time types map from Java to InterSystems IRIS as follows:

Java InterSystems IRIS
java.sql.Date %Library.Date
java.sql.Time %Library.Time
java.sql.Timestamp %Library.TimeStamp

Properties

The result of importing a Java class is an ObjectScript abstract class. For each Java property that does not already have corresponding getter and setter methods (imported as is), the Java Gateway engine generates corresponding ObjectScript getter and setter methods. It generates setters as setXXX, and getters as getXXX, where XXX is the property name. For example, importing a Java string property called Name results in a getter method getName() and a setter method setName(%Library.String). The gateway also generates set and get class methods for all static members.

Methods

After you perform the Java Gateway import operation, all methods in the resulting InterSystems IRIS proxy class have the same name as their Java counterparts, subject to the limitations described in the Method Names section. They also have the same number of arguments. The type for all the InterSystems IRIS proxy argument methods is %Library.ObjectHandle; the Java Gateway engine resolves types at runtime.

For example, the Java method test():

public boolean checkAddress(Person person, Address address)
Copy code to clipboard

is imported as:

Method checkAddress(p0 As %Library.ObjectHandle,
                    p1 As %Library.ObjectHandle) As %Library.ObjectHandle
Copy code to clipboard

Overloaded Methods

While ObjectScript does not support overloading, you can still map overloaded Java methods to InterSystems IRIS proxy classes. This is supported through a combination of largest method cardinality and default arguments. For example, if you are importing an overloaded Java method whose different versions take two, four, and five arguments, there is only one corresponding method on the InterSystems IRIS side; that method takes five arguments, all of %ObjectHandle type. You can then invoke the method on the InterSystems IRIS side with two, four, or five arguments. The Java Gateway engine then tries to dispatch to the right version of the corresponding Java method.

While this scheme works reasonably well, avoid using overloaded methods with the same number of arguments of similar types. For example, the Java Gateway has no problems resolving the following methods:

test(int i, String s, float f)
test(Person p)
test(Person p, String s, float f)
test(int i)
Copy code to clipboard

However, avoid the following:

test(int i)
test(float f)
test(boolean b)
test(Object o)
Copy code to clipboard
Tip:

For better results using the Java Gateway, use overloaded Java methods only when absolutely necessary.

Method Names

InterSystems IRIS has a limit of 31 characters for method names. Ensure your Java method names are not longer than 31 characters. If the name length is over the limit, the corresponding InterSystems IRIS proxy method name contains only the first 31 characters of your Java method name. For example, if you have the following methods in Java:

thisJavaMethodHasAVeryVeryLongName(int i)       // 34 characters long
thisJavaMethodHasAVeryVeryLongNameLength(int i) // 40 characters long
Copy code to clipboard

InterSystems IRIS imports only one method with the following name:

thisJavaMethodHasAVeryVeryLongN                 // 31 characters long
Copy code to clipboard

The Java reflection engine imports the first one it encounters. To find out which method is imported, you can check the InterSystems IRIS proxy class code. Better yet, ensure that logging is turned on before the import operation. The Java Gateway log file contains warnings of all method names that were truncated or not imported for any reason.

Each underscore (_) in an original method name is replaced with the character u and each dollar sign ($) is replaced with the character d. Both the u and the d are case-sensitive (lowercase). If these conventions cause an unintended overlap with another method name that already exists on the InterSystems IRIS side, the method is not imported.

Finally, InterSystems IRIS class code is not case-sensitive. So, if two Java method names differ only in case, InterSystems IRIS only imports one of the methods and writes the appropriate warnings in the log file.

Static Methods

Java static methods are projected as class methods in the InterSystems IRIS proxy classes. To invoke them from ObjectScript, use the following syntax:

  // calls static Java method staticMethodName(par1,par2,...)
  Do ##class(className).staticMethodName(gateway,par1,par2,)
Copy code to clipboard

Constructors

You invoke Java constructors by calling %New(). The signature of %New() is exactly the same as the signature of the corresponding Java constructor, with the addition of one argument in position one: an instance of the Java Gateway. The first thing %New() does is to associate the proxy instance with the provided gateway instance. It then calls the corresponding Java constructor. For example:

 // calls Student(int id, String name) Java constructor
 Set Student=##class(javagateway.Student).%New(Gateway,29,"John Doe")
Copy code to clipboard

Constants

The Java Gateway projects and imports Java static final variables (constants) as Final Parameters. The names are preserved when imported, except that each underscore (_) is replaced with the character u and each dollar sign ($) is replaced with the character d. Both the u and the d are case-sensitive (lowercase).

For example, the following static final variable:

public   static   final   int   JAVA_CONSTANT   =  1;
Copy code to clipboard

is mapped in ObjectScript as:

Parameter JAVAuCONSTANT  As INTEGER = 1;
Copy code to clipboard

From ObjectScript, access the parameter as:

##class(MyJavaClass).%GetParameter("JAVAuCONSTANT"))
Copy code to clipboard

Java Classes

The following sections describe the particulars of using the InterSystems IRIS Java Gateway with specific types of Java classes:

Java Object Superclass (java.lang.Object)

Earlier versions of the Java Gateway did not allow the use of java.lang.Object. This release maps java.lang.Object as is. When using java.lang.Object, consider the following:

  • Primitive wrapper classes in Java, which are subclasses of java.lang.Object in Java, are mapped to InterSystems IRIS data types and are thus not subclasses of java.lang.Object in InterSystems IRIS. For details, see the Java Arrays section.

  • Although using java.lang.Object in Java provides great flexibility, it often requires much (re)casting. ObjectScript has only limited support for casting and recasting. When using java.lang.Object to point to its subclass, use the cast operation in ObjectScript to execute the methods of the subclass. Here is an example from the EJB Gateway:

     Set jndiContext=##class(javax.naming.InitialContext).%New(gateway)
     Set jndiName="PersonEJB_Sample_EJBPerson"
     Set refPerson=jndiContext.lookup(jndiName)
     Set personHomeClass=##class(java.lang.Class).forName(gateway,
         Sample.EJBPersonHome)
     Set homePerson=##class(javax.rmi.PortableRemoteObject).narrow(gateway,
        refPerson,personHomeClass)
     // here homePerson is java.lang.Object, and in Java, we would simply
     // recast it to EJBPersonHome by saying:
     //    homePerson = (EJBPersonHome) homePerson
    
     // In ObjectScript, you will need to 'recast' the method call:
     Set remotePerson=##class(Sample.EJBPersonHome)homePerson.findById(1)
    Copy code to clipboard

Using java.lang.Object works as long as you remember you cannot recast an object per se. However, since InterSystems IRIS proxy classes are abstract classes, method invocation recasting is sufficient for most purposes.

Java Arrays

Arrays of primitive types, wrappers, data and time types, and Class types are mapped as %Library.ListOfDataTypes. Arrays of object types are mapped as %Library.ListOfObjects. Only one level of subscripts is supported.

Java byte arrays (byte[]) are projected as %Library.GlobalBinaryStream. Similarly, Java char arrays (char[]) are projected as %Library.GlobalCharacterStream. This allows for a more efficient handling of byte and character arrays.

As an only exception to the general rule of pass-by-value-only semantics in the Java Gateway, you can pass byte and stream arrays either by value or by reference. Passing by reference allows changes to the byte/char stream on the Java side visible on the InterSystems IRIS side as well. A good example is the java.io.InputStream read method:

int read(byte ba[], int maxLen

which reads up to maxLen bytes into the ba byte array. For example, in Java:

byte[] ba = new byte[maxLen];
int bytesRead = inputStream.read(ba,maxLen);
Copy code to clipboard

The equivalent code in ObjectScript:

 Set readStream=##class(%GlobalBinaryStream).%New()
 // reserve a number of bytes since we are passing the stream by reference
 For i=1:1:50 Do readStream.Write("0")
 Set bytesRead=test.read(.readStream,50)
Copy code to clipboard

The following example passes a character stream by value, meaning that any changes to the corresponding Java char[] are not reflected on the InterSystems IRIS side:

 Set charStream=##class(%GlobalCharacterStream).%New()
 Do charStream.Write("Global character stream")
 Do test.setCharArray(charStream)
Copy code to clipboard

Java Collections Framework

Previous versions of the Java Gateway provided special treatment when importing java.util.List (and its subclasses), java.util.Map (and its subclasses) and java.util.Class. The Java Gateway imported the first two as either %Library.ListOfDataTypes or %Library.ListOfObjects and java.util.Class as %Library.String.

This release now imports all of the above classes “as is.” You now can use the entire Java Collections Framework “as is” in InterSystems IRIS. You can also take advantage of java.lang.Class methods. The following is a HashMap example using ObjectScript:

 Set grades=##class(java.util.HashMap).%New(gateway)
 Set x=grades.put("Biology",3.8)

 Set x=grades.put("Spanish",2.75)
 Do student.mySetGrades(grades)

 Set grades=student.myGetGrades()
 Set it=grades.keySet().iterator()
 While (it.hasNext()) {
     Set key=it.next()
     Set value=grades.get(key)
     Write " ",key," ",value,!
 }
Copy code to clipboard

The following example uses Class.forName and java.utilArrayList:

 Set arrayListCls=##class(java.lang.Class).forName(gateway,"java.util.ArrayList")
 Set sports=arrayListCls.newInstance()
 Do sports.add("Basketball")

 Do sports.add("Swimming")

 Set list=student.myGetFavoriteSports()
     For i=0:1:list.size()-1 {
     Write " "_list.get(i),!
 }
Copy code to clipboard

Recasting

ObjectScript has limited support for recasting; namely, you can recast only at a point of a method invocation. However, since all InterSystems IRIS proxies are abstract classes, this should be quite sufficient. For an example of how to recast, see the Java Object Superclass section.

Java Standard Output Redirection

The Java Gateway automatically redirects any standard Java output in the corresponding Java code to the calling InterSystems IRIS session. It collects any calls to System.out in your Java method calls and sends them to InterSystems IRIS to display in the same format as you would expect to see if you ran your code from Java. To disable this behavior and direct your output to the standard output device as designated by your Java code (in most cases that would be the console), set the following global reference in your interoperability-enabled namespace:

 Set ^%SYS("Gateway","Remote","DisableOutputRedirect") = 1
Copy code to clipboard

Restrictions

Important:

Rather than aborting import, the Java Gateway engine silently skips over all the members it is unable to generate. If you repeat the import step with logging turned on, InterSystems IRIS records all skipped members (along with the reason why they were skipped) in the WARNING section of the log file.

The Java Gateway engine always makes an attempt to preserve package and method names, parameter types, etc. That way, calling an InterSystems IRIS proxy method is almost identical to calling the corresponding method in Java. It is therefore important to keep in mind ObjectScript restrictions and limits while writing your Java code. In a vast majority of cases, there should be no issues at all. You might run into ObjectScript limits if, for example:

  • Your Java method names are longer than 30 characters.

  • You have 100 or more arguments.

  • You are trying to pass String objects longer than 32K.

  • You rely on the fact that Java is case-sensitive when you choose your method names.

  • You are trying to import a static method that overrides an instance method.

Check with the latest ObjectScript documentation regarding any limits or restrictions. The books are: