Oracle8i SQLJ Developer's Guide and Reference
Release 2 (8.1.6)

A81360-01

Library

Product

Contents

Index

Prev  Chap Top Next

Custom Java Classes

The purpose of custom Java classes is to provide a way to convert data between the database and your Java application and make the data accessible, particularly in supporting objects and collections or if you want to perform custom data conversions.

It is generally advisable to provide custom Java classes for all user-defined types (objects and collections) that you use in a SQLJ application. The Oracle JDBC driver will use instances of these classes in converting data, which is more convenient and less error-prone than using the weakly typed oracle.sql.STRUCT, REF, and ARRAY classes.

Custom Java classes are first-class types that you can use to read from and write to user-defined SQL types transparently.

To be used in SQLJ iterators or host expressions, a custom Java class must implement either the oracle.sql.CustomDatum (and CustomDatumFactory) interface or the standard java.sql.SQLData interface. This section provides an overview of these interfaces and custom Java class functionality, covering the following topics:

Custom Java Class Interface Specifications

This section discusses specifications of the CustomDatum and CustomDatumFactory interfaces and of the SQLData interface.

CustomDatum and CustomDatumFactory Specifications

Oracle provides the interface oracle.sql.CustomDatum and the related interface oracle.sql.CustomDatumFactory to use in mapping and converting Oracle object types, reference types, and collection types to custom Java classes.

Data is passed to or from the database in the form of an oracle.sql.Datum object, with the underlying data being in the format of the appropriate oracle.sql.Datum subclass--oracle.sql.STRUCT, for example. This data is still in its codified database format; the oracle.sql.Datum object is just a wrapper. (For information about classes in the oracle.sql package that support Oracle type extensions, see the Oracle8i JDBC Developer's Guide and Reference.)

The CustomDatum interface specifies a toDatum() method for data conversion from Java format to database format. This method takes as input your OracleConnection object (which is required by the Oracle JDBC drivers) and converts data to the appropriate oracle.sql.* representation. The OracleConnection object is necessary so that the JDBC driver can perform appropriate type checking and type conversions at runtime. Here is the CustomDatum and toDatum() specification:

interface oracle.sql.CustomDatum
{
   oracle.sql.Datum toDatum(OracleConnection c);
}

The CustomDatumFactory interface specifies a create() method that constructs instances of your custom Java class, converting from database format to Java format. This method takes as input a Datum object containing data from the database, and a typecode, such as OracleTypes.RAW, indicating the SQL type of the underlying data. It returns an object of your custom Java class, which implements the CustomDatum interface. This object receives its data from the Datum object that was input. Here is the CustomDatumFactory and create() specification:

interface oracle.sql.CustomDatumFactory
{
   oracle.sql.CustomDatum create(oracle.sql.Datum d, int sqlType);
}

To complete the relationship between the CustomDatum and CustomDatumFactory interfaces, you must implement a static getFactory() method in any custom Java class that implements the CustomDatum interface. This method returns an object that implements the CustomDatumFactory interface and that, therefore, can be used to create instances of your custom Java class. This returned object can itself be an instance of your custom Java class, and its create() method is used by the Oracle JDBC driver to produce further instances of your custom Java class, as necessary.


Note:

JPublisher implements CustomDatum and its toDatum() method and CustomDatumFactory and its create() method in a single custom Java class; however, toDatum() and create() are specified in different interfaces to allow the option of implementing them in separate classes. You can have one custom Java class that implements CustomDatum, its toDatum() method, and the getFactory() method, and have a separate factory class that implements CustomDatumFactory and its create() method. For purposes of discussion here, though, the assumption is that both interfaces are implemented in a single class.  


For information about Oracle SQLJ requirements of a class that implements CustomDatum, see "Oracle Requirements for Classes Implementing CustomDatum".

For more information about the CustomDatum and CustomDatumFactory interfaces, the oracle.sql classes, and the OracleTypes class, see the Oracle8i JDBC Developer's Guide and Reference.

If you use JPublisher, specifying -usertypes=oracle will result in JPublisher generating custom Java classes that implement the CustomDatum and CustomDatumFactory interfaces and the getFactory() method.

SQLData Specification

Standard JDBC 2.0 provides the interface java.sql.SQLData to use in mapping and converting structured object types to Java classes. This interface is intended for mapping structured object types only, not object references, collections/arrays, or other SQL types.

The SQLData interface is a JDBC 2.0 standard, specifying a readSQL() method to read data from the database into a Java object, and a writeSQL() method to write data to the database from a Java object.

For information about Oracle-specific functionality that is required of a class that implements SQLData, see "Oracle Requirements for Classes Implementing SQLData".

For information about standard SQLData functionality, refer to the Sun Microsystems JDBC 2.0 API specification.

If you use JPublisher, specifying -usertypes=jdbc will result in JPublisher generating custom Java classes that implement the SQLData interface.

Custom Java Class Support for Object Methods

Methods of Oracle objects can be implemented as wrappers in custom Java classes. Whether the underlying stored procedure is written in PL/SQL or is written in Java and published to SQL is invisible to the user.

A Java wrapper method used to invoke a server method requires a connection to communicate with the server. The connection object can be provided as an explicit parameter or can be associated in some other way (as an attribute of your custom Java class, for example).

If the connection object used by the wrapper method is a non-static attribute, then the wrapper method must be an instance method of the custom Java class in order to have access to the connection. Custom Java classes generated by JPublisher use this technique.

There are also issues regarding output and input-output parameters in methods of Oracle objects. In the database, if a stored procedure (SQL object method) modifies the internal state of one of its arguments, then the actual argument passed to the stored procedure is modified. In Java this is not possible. When a JDBC output parameter is returned from a stored procedure call, it is stored in a newly created object. The original object identity is lost.

One way to return an output or input-output parameter to the caller is to pass the parameter as an element of an array. If the parameter is input-output, the wrapper method takes the array element as input; after processing, the wrapper assigns the output to the array element. Custom Java classes generated by JPublisher use this technique--each output or input-output parameter is passed in a one-element array.

When you use JPublisher, it implements wrapper methods by default. This is true for generated classes implementing either the SQLData interface or the CustomDatum interface. To disable this feature, set the JPublisher -methods flag to false. See the Oracle8i JPublisher User's Guide for more information.


Note:

If you are implementing a custom Java class yourself, there are various ways that you can implement wrapper methods. Data processing can be done either in the server in the SQL object method, or on the client in the wrapper method. To see how JPublisher implements wrapper methods, and whether this may meet your needs, see "JPublisher Implementation of Wrapper Methods".  


Custom Java Class Requirements

Custom Java classes must satisfy certain requirements to be recognized by the Oracle SQLJ translator as valid host variable types, and to allow type-checking by the translator.

This section discusses Oracle-specific requirements of custom Java classes so they can support this functionality. Requirements for both CustomDatum implementations and SQLData implementations are covered.

Oracle Requirements for Classes Implementing CustomDatum

Oracle requirements for CustomDatum implementations are primarily the same for any kind of custom Java class but vary slightly depending on whether the class is for mapping to objects, object references, collections, or some other SQL type.

These requirements are as follows:

Oracle Requirements for Classes Implementing SQLData

It is important to note that in release 8.1.6, Oracle SQLJ has one non-standard requirement of a class that implements SQLData:

This permits SQLJ to accomplish type-checking during translation. In future releases, this will be accomplished by some standard implementation.


Notes:

  • Because the custom Java class defines _SQL_NAME, the connection instance (or specified) type map that is normally used to map user-defined SQL types to Java types for SQLData implementations is neither required nor used by Oracle SQLJ.

  • SQLData, unlike CustomDatum, is for mapping structured object types only. It is not for object references, collections/arrays, or any other SQL types. If you are not using CustomDatum, then your only choices for mapping object references and collections are the weak types java.sql.Ref and java.sql.Array, respectively (or oracle.sql.REF and oracle.sql.ARRAY).

  • SQLData implementations require a JDK 1.2.x environment. Although Oracle JDBC supports JDBC 2.0 extensions under JDK 1.1.x through the oracle.jdbc2 package, Oracle SQLJ does not.

 

Compiling Custom Java Classes

You can include the .java file names for your custom Java classes (whether CustomDatum or SQLData implementations) on the SQLJ command line, together with your .sqlj file names. However, this is not necessary if the SQLJ -checksource flag is set to true (the default) and your CLASSPATH includes the directory where the custom Java source is located.

For example, if ObjectDemo.sqlj uses Oracle object types ADDRESS and PERSON and you have run JPublisher or otherwise produced custom Java classes for these objects, then you can run SQLJ as follows.

If -checksource=true (default) and CLASSPATH includes custom Java source location:

% sqlj ObjectDemo.sqlj

Or, if -checksource=false:

% sqlj ObjectDemo.sqlj Address.java AddressRef.java Person.java PersonRef.java

Alternatively, you can use your Java compiler to compile the custom Java source files directly. If you do this, it must be done prior to translating the .sqlj file.

Running the SQLJ translator is discussed in Chapter 8, "Translator Command Line and Options". For more information about the -checksource flag, see "Source Check for Type Resolution (-checksource)".


Note:

Because CustomDatum implementations rely on Oracle-specific features, SQLJ will report numerous portability warnings if you do not use the translator portability setting -warn=noportable (the default). For information about the -warn flag, see "Translator Warnings (-warn)".  


Reading and Writing Custom Data

Through the use of custom Java class instances, Oracle SQLJ and JDBC allow you to read and write user-defined types as though they are built-in types. Exactly how this is accomplished is transparent to the user.

For the mechanics of how data is read and written, for both CustomDatum implementations and SQLData implementations, see the Oracle8i JDBC Developer's Guide and Reference.

Additional Uses for CustomDatum Implementations

To this point, discussion of custom Java classes has been for use as one of the following:

It might be useful, however, to provide custom Java classes to wrap other oracle.sql.* types as well, for customized conversions or processing. You can accomplish this with classes that implement CustomDatum (but not SQLData), as in the following examples:

This last use is further discussed in "Serializing Java Objects through Custom Java Classes".

"General Use of CustomDatum--BetterDate.java" provides an example of a class (BetterDate) that implements CustomDatum and can be used instead of java.sql.Date to represent dates.


Note:

This sort of functionality is not possible through the SQLData interface, as SQLData implementations can wrap only structured object types.  





Prev

Top

Next
Oracle
Copyright © 1999 Oracle Corporation.

All Rights Reserved.

Library

Product

Contents

Index