Skip to main content

Java Proxy Class Mapping

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.PersistentOpens in a new tab 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:

  • If the method name starts with "%", this is replaced by "sys_".

  • If the method name is a Java reserved word, "_" is prepended to the name.

  • For methods of classes that are part of the %Library package, the leading "%" is replaced with a "_" and the first letter is converted to lowercase.

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:

  • _close() — Shuts down an object on the server from the client (by invoking the object's %Close method).

  • _open() — For persistent objects, open an instance of object stored within the database using the instance's OID as a handle.

  • _openId() — For persistent objects, open an instance of object stored within the database using the instance's class ID value as a handle.

Passing Null Values and Empty Strings

It is important to remember that Caché represents null values and empty strings differently:

  • A Caché NULL value is represented as "" (an empty string).

  • A Caché empty string is represented as character $c(0).

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.

FeedbackOpens in a new tab