Using Java with Caché
Java Proxy Class Mapping
[Home] [Back] 
InterSystems: The power behind what matters   
Class Reference   
Search:    

The Caché Java binding reads the definition of a Caché class and uses the information to generate a corresponding Java class. The generated class provides remote access to an instance of a Caché object from within a Java application. This chapter describes how Caché objects and data types are mapped to Java code, and provides details on the objects and methods provided by the Caché Java binding.

Classes
The projections of Caché classes receive names as Java classes in accordance with the naming conventions listed below. The type of a class (such as persistent or serial) determines its corresponding Java superclass. For example, persistent classes have corresponding Java classes derived from the Java Persistent class.
Entity Names
A Caché identifier, such as class or method name, is usually projected to a corresponding Java identifier with the same name. If a Caché identifier is a Java reserved word, the corresponding Java identifier will preceded by an underscore ("_").
For details on Caché Basic and ObjectScript naming conventions, see Variables in Using Caché ObjectScript, Naming Conventions in Using Caché Objects, Identifiers and Variables in Using Caché Basic, and Rules and Guidelines for Identifiers in the Caché Programming Orientation Guide.
Class Names
All class names are unchanged. All Caché packages become Java packages, and the "%" characters within a package name are translated to "_". In your code, the Caché and Java package names must match each other exactly.
The %Library package is an exception to this rule. There is no one—to—one correspondence between %Library and any of Java library packages, but most common %Library classes have their stubs in the com.intersys.classes package. For example, the %Library.Persistent class would be mapped as "com.intersys.classes.Persistent".
Property Names
You can refer directly to Caché properties. To conform to Java property-handling style, the projection of each Caché property includes two accessor methods: get<Prop>() and set<Prop>(), where <Prop> is the name of the projected property. If the property name starts with "%", it is replaced by "set_". Hence, the projection of the Color property would include getColor() and setColor() methods. The projection of a %Concurrency property would have get_Concurrency() and set_Concurrency() methods.
Method Names
Typically, method names are mapped directly, without changes. Exceptions are:
Formal Variable Names
If a variable within a method formal list starts with "%" it is replaced by "_". If the name is a Java reserved word, "_" is prepended to the name.
Packages
In general, the Caché package name for a class is used as its Java package name. If a Caché class defines a class parameter, JAVAPACKAGE, then the Java Generator uses the parameter value for a package name.
Methods
Methods of Caché classes are projected to Java as stub methods of the corresponding Java classes. Instance methods are projected as Java instance methods; class methods are projected as Java static methods. When called on the client, a method invokes the actual method implementation on the Caché server.
If a method signature includes arguments with default values, the system generates multiple versions of the method with different numbers of arguments to simulate default argument values within Java.
For example, suppose you define a simple Caché class with one method as follows:
   Class MyApp.Simple Extends %RegisteredObject {
      Method LookupName(id As %String) As %String {
         // lookup a name using embedded SQL
         Set name = ""
         &sql(SELECT Name INTO :name FROM Person WHERE ID = :id)
         Quit name
      }
   }
The resulting projected Java class would look something like:
   public class Simple extends Object {
      //...
      public String LookupName(String id) throws CacheException {
         // generated code to invoke method remotely...
         // ...
         return typedvalue;
      }
   }
When a projected method is invoked from Java, the Java client first synchronizes the server object cache, then invokes the method on the Caché server, and, finally, returns the resulting value (if any). If any method arguments are specified as call by reference then their value is updated as well.
System Methods
In addition to any methods defined by a Caché class, the projected Java class includes a number of automatically generated system methods to perform various services:
Passing Null Values and Empty Strings
It is important to remember that Caché represents null values and empty strings differently:
This may seem counter-intuitive to many Java programmers, but is consistent with the way NULL is treated in SQL.
An empty string returned from a method with a non-string return type is converted to a null value, making it necessary to perform a null check on the returned value before using the corresponding object. For example the following line of code could throw a NullPointerException:
   return myCacheObject.getMyInteger().intValue();
To avoid this, you would perform the following check:
   Integer myInteger = myCacheObject.getMyInteger();
      if (myInteger == null) {
         // handle null value here
      } else
   return myInteger.intValue();
This is also true for parameters returned by reference.
Properties
You can refer to each of a projection's properties using its two accessor methods: get<Prop>() to get its value and set<Prop>() to set its value.
The values for literal properties (such as strings or integers) are represented using the appropriate Java data type classes (such as String or Integer).
The values for object-valued properties are represented using the appropriate projected Java class. In addition to the get and set methods, an object-valued property has additional methods that provide access to the persistent object ID for the object: idset<Prop>() and idget<Prop>().
For example, suppose you have defined a persistent class within Caché containing two properties, one literal and the other object-valued:
   Class MyApp.Student Extends %Persistent {
      /// Student's name
      Property Name As %String;
      /// Reference to a school object
      Property School As School;
   }
The Java representation of MyApp.Student contains get and set accessors for both the Name and School properties. In addition, it provides accessors for the Object Id for the referenced School object.
   public class Student extends Persistent {
      // ...
      public String getName() throws CacheException {
         // implementation...
      }
      public void setName(String value) throws CacheException {
         // implementation...
      }
      public School getSchool() throws CacheException {
         // implementation...
      }
      public void setSchool(School value) throws CacheException {
         // implementation...
      }
      public Id idgetSchool() throws CacheException {
         // implementation...
      }
      public void idsetSchool(Id value) throws CacheException {
         // implementation...
      }
   }
Property Caching
When a projected Java object is instantiated within Java, it fetches a copy of its property values from the Caché server and copies them into a local Java-side cache. Subsequent access to the object's property values are made against this cache, reducing the number of messages sent to and from the server. Caché automatically manages this local cache and ensures that it is synchronized with the corresponding object state on the Caché server.
Property values for which you have defined a get or set method within your Caché class definition (such as for a property whose value depends on other properties) are not stored within the local cache. Instead, when you access such properties the corresponding accessor method is invoked on the Caché server. As this can entail higher network traffic, exercise care when using such properties in a Java environment.
Primitive Data Types
Caché uses various literal data types (such as strings or numbers) for properties, method return types, and method arguments. Every Caché data type has an associated client data type. This client data type specifies the Java class to which a variable is mapped. Hence, using its client data type, every Caché data type is represented using an appropriate Java object such as Integer or String.
Regardless of a property's type, if it has unset value, then Java represents it using the null keyword. For example, suppose you create a new object with an Age property that is of type Integer. Prior to setting this property's value, invoking the getAge() method returns null.
By default, the CLIENTDATATYPE keyword value of a Caché data type determines which Java class is associated with it. The following table describes this correspondence:
Client Data Type to Java Correspondence
ClientDataType
Java Class
Java Package
HolderClass
BINARY
byteArray
null
ByteArrayHolder
BOOLEAN
Boolean
java.lang
BooleanHolder
CURRENCY
BigDecimal
java.math
BigDecimalHolder
DATE
Date
java.sql
DateHolder
DOUBLE
Double
java.lang
DoubleHolder
ID
Id (a Caché-provided class that represents an Object ID within an extent)
com.intersys.objects
IdHolder
INT
Integer
java.lang
IntegerHolder
LIST
SysList (A Java implementation of Caché $List structure)
com.intersys.objects
SysListHolder
LONG VARCHAR
String
java.lang
StringHolder
NUMERIC
BigDecimal
java.math
BigDecimalHolder
OID
Oid (a Caché-provided class that represents a complete Object ID)
com.intersys.objects
OidHolder
STATUS
StatusCode (a Caché-provided class that represents the status)
com.intersys.objects
StatusCodeHolder
TIME
Time
java.sql
TimeHolder
TIMESTAMP
TimeStamp
java.sql
TimeStampHolder
VARCHAR
String
java.lang
StringHolder
Void
void
null
null
Object-valued types (references to other object instances) are represented using the corresponding Java class. Certain Caché objects are treated as special cases. For example, streams are mapped to the Java stream object, and collections are projected as collection objects (a class created by InterSystems for Java client use). If a method argument is passed by reference then a “holder” class is used, such as IntegerHolder or StringHolder.
The JAVATYPE parameter allows you to override the default value and associate a property with a specified client Java class.