Skip Headers

Oracle® Database JPublisher User's Guide
10g Release 1 (10.1)

Part Number B10983-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Feedback

Go to previous page
Previous
Go to next page
Next
View PDF

3 Generated Classes and Interfaces

This chapter discusses details and concepts of the classes, interfaces, and subclasses that JPublisher generates, including how output parameters are treated (PL/SQL IN OUT or OUT parameters), how overloaded methods are translated, and how to use the generated classes and interfaces. The following topics are covered:

JPublisher Treatment of Output Parameters

Stored procedures called through JDBC do not have the same parameter-passing behavior as ordinary Java methods. This affects the code you write when you call a wrapper method that JPublisher generates.

When you call an ordinary Java method, parameters that are Java objects are passed as object references. The method can modify the object.

By contrast, when you call a stored procedure through JDBC, a copy of each parameter is passed to the stored procedure. If the procedure modifies any parameters, copies of the modified parameters are returned to the caller. Therefore, the "before" and "after" values of a modified parameter appear in separate objects.

A wrapper method that JPublisher generates contains JDBC statements to call the corresponding stored procedure. The parameters to the stored procedure, as declared in your CREATE TYPE or CREATE PACKAGE declaration, have three possible parameter modes: IN, OUT, or IN OUT. Parameters that are IN OUT or OUT are returned to the wrapper method in newly created objects. These new values must be returned to the caller somehow, but assignment to the formal parameter within the wrapper method does not affect the actual parameter visible to the caller.

In Java, there are no OUT or IN OUT designations, but values can be returned through holders. In JPublisher, you can specify one of three alternatives for holders that handle PL/SQL OUT or IN OUT parameters:

The -outarguments option enables you to specify which mechanism to use. This feature is particularly useful for Web services. See "Holder Types for Output Arguments (-outarguments)" for syntax information.

The following sections describe the three mechanisms:

Passing Output Parameters in Arrays

The simplest way to solve the problem of returning output values in Java is to pass an OUT or IN OUT parameter to the wrapper method in a single-element array. Think of the array as a "container" that holds the parameter. This mechanism works as follows:

  • You assign the "before" value of the parameter to element [0] of an array.

  • You pass the array to your wrapper method.

  • The wrapper method assigns the "after" value of the parameter to element [0] of the array.

  • After executing the method, you extract the "after" value from the array.

A setting of -outarguments=array (the default) instructs JPublisher to use this single-element array mechanism to publish any OUT or IN OUT argument.

Here is an example:

Person [] pa = {p}; 
x.f(pa); 
p = pa[0]; 

Assume that x is an instance of a JPublisher-generated class that has the method f(), which is a wrapper method for a stored procedure that uses a SQL PERSON object as an IN OUT parameter. The type PERSON maps to the Java class Person; p is a Person instance; and pa[] is a single-element Person array.

The array technique for passing OUT or IN OUT parameters requires you to add a few extra lines of code to your program for each parameter.

As another example, consider the PL/SQL function created by the following SQL*Plus command:

SQL> create or replace function g (a0 number, a1 out number, a2 in out number,
     a3 clob, a4 out clob, a5 in out clob) return clob is begin return null; end;

With -outarguments=array, this is published as follows:

public oracle.sql.CLOB g (
     java.math.BigDecimal a0,
     java.math.BigDecimal a1[],
     java.math.BigDecimal a2[],
     oracle.sql.CLOB a3,
     oracle.sql.CLOB a4[],
     oracle.sql.CLOB a5[])

Problems similar to those described earlier arise when the this object of an instance method is modified.

The this object is an additional parameter, passed in a different way. Its mode, as declared in the CREATE TYPE statement, may be IN or IN OUT. If you do not explicitly declare the mode of this, its mode is IN OUT if the stored procedure does not return a result, or IN if it does.

If the mode of the this object is IN OUT, then the wrapper method must return the new value of this. The code generated by JPublisher implements this functionality in different ways, depending on the situation:

  • For a stored procedure that does not return a result, the new value of this is returned as the result of the wrapper method.

    As an example, assume that the SQL object type MYTYPE has the following member procedure:

    MEMBER PROCEDURE f1(y IN OUT INTEGER);
    
    

    Also assume that JPublisher generates a corresponding Java class, MyJavaType. This class defines the following method:

    MyJavaType f1(int[] y)
    
    

    The f1() method returns the modified this object value as a MyJavaType instance.

  • For a stored function (a stored procedure that returns a result), the wrapper method returns the result of the stored function as its result. The new value of this is returned in a single-element array, passed as an extra argument (the last argument) to the wrapper method.

    Assume that the SQL object type MYTYPE has the following member function:

    MEMBER FUNCTION f2(x IN INTEGER) RETURNS VARCHAR2;
    
    

    Then the corresponding Java class, MyJavaType, defines the following method:

    String f2(int x, MyJavaType[] newValue)
    
    

    The f2() method returns the VARCHAR2 function-return as a Java string, and returns the modified this object value as an array element in the MyJavaType array.


Note:

For PL/SQL static procedures or functions, JPublisher generates instance methods, not static methods, in the wrapper class. This is the logistic for associating a database connection with each wrapper class instance. The connection instance is used in initializing the wrapper class instance so that you are not subsequently required to explicitly provide a connection or connection context instance when calling wrapper methods.

Passing Output Parameters in JAX-RPC Holders

The JAX-RPC specification explicitly specifies holder classes in the javax.xml.rpc.holders package for the Java mapping of simple XML data types and other types. Typically, "Holder" is appended to the type name for the holder class name. For example, BigDecimalHolder is the holder class for BigDecimal.

Given a setting of -outarguments=holder, JPublisher uses holder instances to publish OUT and IN OUT arguments from stored procedures. Holder settings are specified in a JPublisher style file, in the HOLDER subtag inside the TARGETTYPE section for the appropriate mapping. If no holder class is specified, then JPublisher chooses one according to defaults. See "JPublisher Styles and Style Files" for details about style files.

For general information about JAX-RPC and holders, see the Java API for XML-based RPC, JAX-RPC 1.0 specification, available at the following location:

http://jcp.org/aboutJava/communityprocess/final/jsr101/index.html

As an example, again consider the PL/SQL function created by the following SQL*Plus command:

SQL> create or replace function g (a0 number, a1 out number, a2 in out number,
a3 clob, a4 out clob, a5 in out clob) return clob is begin return null; end;

With -outarguments=holder, the following is an example of how the function is published. In this case, there is an extra level of abstraction—because oracle.sql.CLOB is not supported by Web services, it is mapped to String, the JAX-RPC holder class for which is StringHolder.Assume the following JPublisher command to publish the function g. (The webservices10 style file contains an entry for -outarguments=holder.)

% jpub -u scott/tiger  -s toplevel"(g)":ToplevelG -style=webservices10

Here is the published interface:

public java.lang.String g
              (java.math.BigDecimal a0,
               javax.xml.rpc.holders.BigDecimalHolder _xa1_out_x,
               javax.xml.rpc.holders.BigDecimalHolder _xa2_inout_x,
               java.lang.String a3,
               javax.xml.rpc.holders.StringHolder _xa4_out_x,
               javax.xml.rpc.holders.StringHolder _xa5_inout_x)
throws java.rmi.RemoteException;


Note:

See "JPublisher-Generated Subclasses for Java-to-Java Type Transformations" for further discussion of how JPublisher uses style files and holder classes for Java-to-Java type transformations for PL/SQL output arguments.

Passing Output Parameters in Function Returns

You can use the setting -outarguments=return as a workaround for supporting method signatures in Web services that do not use JAX-RPC holder types or arrays. In a situation in which there is no support for JAX-RPC holders, the -outarguments=return setting allows OUT or IN OUT data to be returned in function results.

Once again, consider the PL/SQL function created by the following SQL*Plus command:

SQL> create or replace function g (a0 number, a1 out number, a2 in out number,
a3 clob, a4 out clob, a5 in out clob) return clob is begin return null; end;

Assume the following JPublisher command (a wraparound command, with output also shown) to publish the function g. Although the webservices10 style file specifies -outarguments=holder, the -outarguments=return setting comes after the -style setting so takes precedence.

% jpub -u scott/tiger  -s toplevel"(g)":ToplevelG -style=webservices10
       -outarguments=return
SCOTT.top_level_scope
ToplevelGUser_g_Out

The JPublisher output acknowledges that it is processing the SCOTT top level, and also indicates the creation of the Java class ToplevelGUser_g_Out to support output values of the function g through return data.


Notes:

  • The "_g_Out" appended to the user class name is according to the JPublisher naming convention when creating a class to contain the output data in the scenario of passing output parameters in function returns. The "_g" reflects the name of the function being processed; the "_Out" reflects the OUT modifier in the corresponding PL/SQL call spec. So ToplevelGUser_g_Out is the Java type created for the output data of the g() method in class ToplevelGUser. (The user class name is according to the naming pattern specified through the webservices10 style file.)

  • Normally, JPublisher output reflects only the names of SQL or PL/SQL entities being processed, but there is no such entity that directly corresponds to ToplevelGUser_g_Out.


JPublisher generates the following interface to take input parameters and return output parameters:

public ToplevelGUser_g_Out g
            (java.math.BigDecimal a0,
             java.math.BigDecimal xxa2_inoutxx,
             java.lang.String a3,
             java.lang.String xxa5_inoutxx)
throws java.rmi.RemoteException;

JPublisher generates the TopLevelGUser_g_Out class as follows:

public class ToplevelGUser_g_Out{
  public ToplevelGUser_g_Out() { }
  public java.math.BigDecimal getA1Out()  { return a1_out; }
  public void setA1Out(java.math.BigDecimal a1_out) { this.a1_out = a1_out; }
  public java.math.BigDecimal getA2Inout()   { return a2_inout; }
  public void setA2Inout(java.math.BigDecimal a2_inout) 
                          { this.a2_inout = a2_inout; }
  public java.lang.String getA4Out()   { return a4_out; }}

The return type ToplevelGUser_g_Out encapsulates the values of the OUT and IN OUT parameters to be passed back to the caller of the function. As in the preceding section, oracle.sql.CLOB is mapped to String by the webservices10 style file.

Translation of Overloaded Methods

PL/SQL, like Java, lets you create overloaded methods, meaning two or more methods with the same name but different signatures. Overloaded methods with different signatures in PL/SQL may have identical signatures in Java, however, especially in user subclasses. As an example, consider the following PL/SQL stored procedures.

procedure foo(x sys.xmltype);
procedure foo(x clob);
procedure foo(x nchar);

If you process these with a JPublisher setting of -style=webservices-common, then they will all have the same signature in Java:

void foo(String x);
void foo(String x);
void foo(String x);

(See "Style File Specification and Locations" for information about -style settings and properties files.)

JPublisher solves such naming conflicts by appending the first letter of the return type (as applicable) and the first letter of each argument type (as applicable) to the method name. If conflicts still remain, a number is also appended. JPublisher solves the preceding conflict as follows:

void foo(String x);
void fooS(String x);
void fooS1(String x);

Note that PL/SQL does not allow overloading for types from the same family. The following, for example, is illegal:

procedure foo(x decimal);
procedure foo(x int);
procedure foo(x integer);

Now consider the procedures as functions instead, with return types from the same family. The following example is allowed because the argument types are different:

function foo(x float) return decimal;
function foo(x varchar2) return int;
function foo(x Student_T) return integer;

By default, these are mapped into Java methods as follows:

java.math.BigDecimal foo(Float x);
java.math.BigDecimal foo(String x);
java.math.BigDecimal foo(StudentT x);

JPublisher allows them all to be named foo() because now the signatures differ. However, if you want all method names to be unique (as is required for Web services, for example), use the unique setting of the JPublisher -methods option. With -methods=unique, JPublisher publishes the methods as follows, using the naming mechanism described earlier:

java.math.BigDecimal foo(Float x);
java.math.BigDecimal fooBS(String x);
java.math.BigDecimal fooBS1(StudentT x);

See "Generation of Package Classes and Wrapper Methods (-methods)" for additional information about the -methods option.

JPublisher Generation of SQLJ Classes


Note:

The term SQLJ classes refers to Java classes that call the Oracle SQLJ runtime APIs. By default in Oracle Database 10g, .sqlj source files are invisible to the user, being translated automatically and deleted. (If desired, however, you can use settings of the JPublisher -compatible option to generate visible .sqlj files, skipping the automatic translation.)

Also see "JPublisher Usage of the Oracle SQLJ Implementation" and "Backward Compatibility Option".


When -methods=all (the default) or -methods=true, JPublisher typically generates SQLJ classes for PL/SQL packages and for object types, using both ORAData and SQLData implementations. The exception is that a SQLJ class is not generated if an object type does not define any methods, in which case the generated Java class does not require the SQLJ runtime.

SQLJ classes include wrapper methods that invoke the server methods (stored procedures) of object types and packages. This section describes how to use these classes.

Important Notes About Generation of SQLJ Classes

Note the following for JPublisher-generated SQLJ classes:

  • If you are generating Java wrapper classes for a SQL type hierarchy, and any one (or more) of the types contains stored procedures, then by default JPublisher generates SQLJ classes for all the SQL types, not just the types that have stored procedures. (But you have the option of explicitly suppressing the generation of SQLJ classes through the JPublisher -methods=false setting. This results in all non-SQLJ classes.)

  • Classes produced by JPublisher include a release() method. If an instance of a JPublisher-generated wrapper class implicitly constructs a DefaultContext instance, then you should use the release() method to release this connection context instance when it is no longer needed. You can avoid this scenario, however, by adhering to at least one of the following suggestions in creating and using the wrapper class instance:

    • Construct the wrapper class instance with an explicitly provided SQLJ connection context.

    • Explicitly associate the wrapper class instance with a SQLJ connection context instance through the setConnectionContext() method.

    • Implicitly use the static SQLJ default connection context instance for the wrapper class instance. This occurs if you do not supply any connection information.

    See "More About Connection Contexts and Instances in SQLJ Classes" for additional information.

  • In Oracle8i compatibility mode, instead of the constructor taking a DefaultContext instance or user-specified-class instance, there is a constructor that simply takes a ConnectionContext instance. This could be an instance of any class that implements the standard sqlj.runtime.ConnectionContext interface, including the DefaultContext class.

Use of SQLJ Classes That JPublisher Generates for PL/SQL Packages

Take the following steps to use a class that JPublisher generates for a PL/SQL package:

  1. Construct an instance of the class.

  2. Call the wrapper methods of the class.

The constructors for the class associate a database connection with an instance of the class. One constructor takes a SQLJ DefaultContext instance (or an instance of a class specified through the -context option when you ran JPublisher); one constructor takes a JDBC Connection instance; one constructor has no arguments. Calling the no-argument constructor is equivalent to passing the SQLJ default context to the constructor that takes a DefaultContext instance. JPublisher provides the constructor that takes a Connection instance for the convenience of JDBC programmers unfamiliar with SQLJ concepts such as connection contexts and the default context.


Important:

See the preceding section, "Important Notes About Generation of SQLJ Classes".

The wrapper methods are all instance methods, because the connection context in the this object is used in the wrapper methods.

Because a class generated for a PL/SQL package has no instance data other than the connection context, you will typically construct one class instance for each connection context that you use. If the default context is the only one you use, then you can call the no-argument constructor once.

An instance of a class generated for a PL/SQL package does not contain copies of PL/SQL package variables. It is not an ORAData class or a SQLData class, and you cannot use it as a host variable.

Use of SQLJ Classes That JPublisher Generates for Object Types

To use an instance of a Java class that JPublisher generates for a SQL object type or a SQL OPAQUE type, you must first initialize the Java object. You can accomplish this in one of the following ways:

  • Assign an already initialized Java object to your Java object.

  • Retrieve a copy of a SQL object into your Java object. You can do this by using the SQL object as an OUT argument or as the function return of a JPublisher-generated wrapper method, or by retrieving the SQL object through JDBC calls that you write (or through SQLJ #sql statements, if you are in a backward compatibility mode and using SQLJ source files directly).

  • Construct the Java object with the no-argument constructor and set its attributes using the setXXX() methods, or construct the Java object with the constructor that accepts values for all the object attributes. Typically, you will subsequently use the setConnection() or setConnectionContext() method to associate the object with a database connection before invoking any of its wrapper methods. If you do not explicitly associate the object with a JDBC or SQLJ connection before invoking a method on it, then it becomes implicitly associated with the SQLJ default context.

    Other constructors for the class associate a connection with the class instance. One constructor takes a DefaultContext instance (or an instance of a class specified through the -context option when you ran JPublisher), and one constructor takes a Connection instance. The constructor that takes a Connection instance is provided for the convenience of JDBC programmers unfamiliar with SQLJ concepts such as connection contexts and the default context.

Once you have initialized your Java object, you can do the following:

  • Call the accessor methods of the object.

  • Call the wrapper methods of the object.

  • Pass the object to other wrapper methods.

  • Use the object as a host variable in JDBC calls (or in SQLJ #sql statements if you are in a backward compatibility mode and using SQLJ source files directly).

There is a Java attribute for each attribute of the corresponding SQL object type, with getXXX() and setXXX() accessor methods for each attribute. The accessor method names are of the form getFoo() and setFoo() for attribute foo. JPublisher does not generate fields for the attributes.

By default, the class includes wrapper methods that invoke the associated Oracle object methods (stored procedures) executing in the server. The wrapper methods are all instance methods, whether or not the server methods are. The DefaultContext in the this object is used in the wrapper methods.

With Oracle mapping, JPublisher generates the following methods for the Oracle JDBC driver to use. These methods are specified in the ORAData and ORADataFactory interfaces:

  • create()

  • toDatum()

These methods are not generally intended for your direct use. In addition, JPublisher generates the methods setFrom(otherObject), setValueFrom(otherObject), and setContextFrom(otherObject) that you can use to copy the value or connection information from one object instance to another.

More About Connection Contexts and Instances in SQLJ Classes


Note:

"Connection context" is a SQLJ term regarding database connections. For those unfamiliar with SQLJ, the term is briefly defined in "JPublisher Usage of the Oracle SQLJ Implementation".

The class that JPublisher uses in creating SQLJ connection context instances depends on how you set the -context option when you run JPublisher, as follows:

  • A setting of -context=DefaultContext (the default) results in JPublisher using instances of the standard sqlj.runtime.ref.DefaultContext class.

  • A setting of a user-defined class that is in the classpath and that implements the standard sqlj.runtime.ConnectionContext interface results in JPublisher using instances of that class.

  • A setting of -context=generated results in declaration of the static connection context class _Ctx in the JPublisher-generated class. JPublisher uses instances of this class for connection context instances. This is appropriate for Oracle8i compatibility mode, but generally not recommended otherwise.

See "SQLJ Connection Context Classes (-context)" for more information about the -context option.


Note:

It is no longer routine (as it was in the Oracle8i version) for JPublisher to declare a connection context instance _ctx. This is used in Oracle8i compatibility mode, however (-compatible=8i or -compatible=both8i), with _ctx being declared as a protected instance of the static connection context class _Ctx.

Unless you have legacy code that depends on _ctx, it is preferable to use the getConnectionContext() and setConnectionContext() methods to retrieve and manipulate connection context instances in JPublisher-generated classes. See the following discussion for more information about these methods.


Consider the following points in using SQLJ connection context instances or JDBC connection instances in instances of JPublisher-generated wrapper classes:

  • Wrapper classes generated by JPublisher provide a setConnectionContext() method that you can use to explicitly specify a SQLJ connection context instance. (This is not necessary if you have already specified a connection context instance through the constructor.)

    This method is defined as follows:

    void setConnectionContext(conn_ctxt_instance);
    
    

    This installs the passed connection context instance as the SQLJ connection context in the wrapper class instance. The connection context instance must be an instance of the class specified through the -context setting for JPublisher connection contexts (typically DefaultContext).

    Note that the underlying JDBC connection must be compatible with the connection used to materialize the database object in the first place. Specifically, some objects may have attributes, such as object reference types or BLOBs, that are valid only for a particular connection.


Note:

Using the setConnectionContext() method to explicitly set a connection context instance avoids the problem of the connection context not being closed properly. This problem occurs only with implicitly created connection context instances.

  • Use either of the following methods of a wrapper class instance, as appropriate, to retrieve a connection or connection context instance.

    • Connection getConnection()

    • ConnCtxtType getConnectionContext()

    The getConnectionContext() method returns an instance of the connection context class specified through the JPublisher -context setting (typically DefaultContext).

    The returned connection context instance may be either an explicitly set instance or one that was created implicitly by JPublisher.


Note:

These methods are available only in generated SQLJ classes. If necessary, you can use the setting -methods=always to ensure that SQLJ classes are produced. See "Generation of Package Classes and Wrapper Methods (-methods)".

  • If no connection context instance is explicitly set for a JPublisher-generated SQLJ class, then one will be created implicitly from the JDBC connection instance when the getConnectionContext() method is called.

    In this circumstance, at the conclusion of processing, use the release() method to free resources in the SQLJ runtime. This prevents a possible memory leak.

The setFrom(), setValueFrom(), and setContextFrom() Methods

JPublisher provides the following utility methods in generated SQLJ classes:

  • setFrom(anotherObject)

    This method initializes the calling object from another object of the same base type, including connection and connection context information. An existing, implicitly created connection context object on the calling object is freed.

  • setValueFrom(anotherObject)

    This method initializes the underlying field values of the calling object from another object of the same base type. This method does not transfer connection or connection context information.

  • setContextFrom(anotherObject)

    This method initializes the connection and connection context information on the calling object from the connection setting of another object of the same base type. An existing, implicitly created, connection context object on the calling object is freed. This method does not transfer any information related to the object value.

Note that there is semantic equivalence between the following:

x.setFrom(y);

and:

x.setValueFrom(y); 
x.setContextFrom(y);

JPublisher Generation of Non-SQLJ Classes

When -methods=false, or when SQL object types do not define any methods, JPublisher does not generate wrapper methods for object types. In this case, the generated class does not require the SQLJ runtime during execution, so JPublisher generates what is referred to as non-SQLJ classes, meaning classes that do not call the SQLJ runtime APIs. All this is true regardless of whether you use an ORAData implementation or a SQLData implementation.


Notes:

  • When -methods=false, JPublisher does not generate code for PL/SQL packages, because they are not useful without wrapper methods.

  • JPublisher generates the same Java code for reference, VARRAY, and nested table types regardless of whether the -methods setting is false or true.


To use an instance of a class that JPublisher generates for an object type when -methods=false—or for a reference, VARRAY, or nested table type—you must first initialize the object.

Similarly to the case with JPublisher-generated SQLJ classes, you can initialize your object in one of the following ways:

Unlike the constructors generated in SQLJ classes, the constructors generated in non-SQLJ classes do not take a connection argument. Instead, when your object is passed to or returned from a JDBC Statement, CallableStatement, or PreparedStatement object, JPublisher applies the connection it uses to construct the Statement, CallableStatement, or PreparedStatement object.

This does not mean you can use the same object with different connections at different times, which is not always possible. An object may have a subcomponent, such as a reference or a BLOB, that is valid only for a particular connection.

To initialize the object data, use the setXXX() methods if your class represents an object type, or the setArray() or setElement() method if your class represents a VARRAY or nested table type. If your class represents a reference type, you can construct only a null reference. All non-null references come from the database.

Once you have initialized your object, you can do the following:

A few methods have not been mentioned yet. You can use the getORADataFactory() method in JDBC code to return an ORADataFactory object. You can pass this ORADataFactory object to the getORAData() method in the classes ArrayDataResultSet, OracleCallableStatement, and OracleResultSet in the oracle.jdbc package. The Oracle JDBC driver uses the ORADataFactory object to create instances of your JPublisher-generated class.

In addition, classes representing VARRAYs and nested tables have methods that implement features of the oracle.sql.ARRAY class:

JPublisher-generated classes for VARRAYs and nested tables do not, however, extend oracle.sql.ARRAY.

With Oracle mapping, JPublisher generates the following methods for the Oracle JDBC driver to use. These methods are specified in the ORAData and ORADataFactory interfaces:

These methods are not generally intended for your direct use; however, you may want to use them if converting from one object reference Java wrapper type to another.

JPublisher Generation of Java Interfaces

JPublisher has the ability to generate interfaces as well as classes. This feature is especially useful for Web services, because it eliminates the necessity to manually create Java interfaces that represent the API from which WSDL content is generated.

"Publishing SQL User-Defined Types" and "Publishing PL/SQL Packages" discuss how to use the JPublisher -sql option to publish user-defined types and PL/SQL packages.

In addition, the -sql option supports the following syntax:

-sql=sql_package_or_type:JavaClass#JavaInterface

or:

-sql=sql_package_or_type:JavaClass:JavaUserSubclass#JavaSubInterface

Whenever an interface name is specified in conjunction with a class, then the public attributes or wrapper methods (or both) of that class are provided in the interface, and the generated class implements the interface.

You can specify an interface for either the generated class or the user subclass, but not both. The difference between an interface for a generated base class and one for a user subclass involves Java-to-Java type transformations. Method signatures in the subclass may be different from signatures in the base class because of Java-to-Java mappings. See "JPublisher Styles and Style Files" for related information.

JPublisher Subclasses

In translating a SQL user-defined type, you may want to enhance the functionality of the custom Java class generated by JPublisher.

One way to accomplish this is to manually add methods to the class generated by JPublisher. However, this is not advisable if you anticipate running JPublisher at some future time to regenerate the class. If you regenerate a class that you have modified in this way, then your changes (that is, the methods you have added) will be overwritten. Even if you direct JPublisher output to a separate file, you still must merge your changes into the file.

The preferred way to enhance the functionality of a generated class is to extend the class. JPublisher has a mechanism for this, where it will generate the original "base" class along with a stub subclass, which you can then customize as desired. Wherever the SQL type is referenced in code (such as where it is used as an argument), the SQL type will be mapped into the subclass, rather than into the base class.

There is also a scenario for JPublisher-generated subclasses for Java-to-Java type transformations. You may have situations in which JPublisher mappings from SQL types to Java types use Java types unsuitable for your purposes—for example, types unsupported by Web services. JPublisher uses a mechanism of "styles" and style files to allow an additional Java-to-Java transformation step in order to use a Java type that is suitable.

These topics are covered in the following sections:

Extending JPublisher-Generated Classes

Suppose you want JPublisher to generate the class JAddress from the SQL object type ADDRESS. You also want to write a class, MyAddress, to represent ADDRESS objects, where MyAddress extends the functionality that JAddress provides.

Under this scenario, you can use JPublisher to generate both a base Java class, JAddress, and an initial version of a subclass, MyAddress, to which you can add the desired functionality. You then use JPublisher to map ADDRESS objects to the MyAddress class instead of the JAddress class.

To do this, JPublisher must alter the code it generates in the following ways:

  • It generates the reference class MyAddressRef rather than JAddressRef.

  • It uses the MyAddress class instead of the JAddress class to represent attributes whose SQL type is ADDRESS, or to represent VARRAY and nested table elements whose SQL type is ADDRESS.

  • It uses the MyAddress factory instead of the JAddress factory when the ORADataFactory interface is used to construct Java objects whose SQL type is ADDRESS.

  • It generates or regenerates the code for the JAddress class. In addition, it generates an initial version of the code for the MyAddress class, which you can then modify to insert your own additional functionality. If the source file for the MyAddress class already exists, however, it is left untouched by JPublisher.


Note:

For information about changes between Oracle8i and Oracle9i for user-written subclasses of classes generated by JPublisher, see "Changes in JPublisher Behavior Between Oracle8i and Oracle9i".

Syntax for Mapping to Alternative Classes

JPublisher has functionality to streamline the process of mapping to alternative classes. Use the following syntax in your -sql command-line option setting:

-sql=object_type:generated_base_class:map_class

For the MyAddress/JAddress example, this is:

-sql=ADDRESS:JAddress:MyAddress

See "Declaration of Object Types and Packages to Translate (-sql)" for information about the -sql option.

If you were to enter the line in the INPUT file instead of on the command line, it would look like this:

SQL ADDRESS GENERATE JAddress AS MyAddress

See "INPUT File Structure and Syntax" for information about the INPUT file.

In this syntax, JAddress is the name of the base class that JPublisher generates, in JAddress.java, but MyAddress is the name of the class that actually maps to ADDRESS. You are ultimately responsible for the code in MyAddress.java. Update this as necessary to add your custom functionality. If you retrieve an object that has an ADDRESS attribute, this attribute is created as an instance of MyAddress. Or, if you retrieve an ADDRESS object directly, it is retrieved into an instance of MyAddress.

Format of the Class that Extends the Generated Class

For convenience, an initial version of the user subclass is automatically generated by JPublisher, unless it already exists. This subclass—generated in MyAddress.java in the preceding example—is where you place your custom code.

Note the following:

  • The class has a no-argument constructor. The easiest way to construct a properly initialized object is to invoke the constructor of the superclass, either explicitly or implicitly.

  • The class implements the ORAData interface or the SQLData interface. This happens implicitly by inheriting the necessary methods from the superclass.

  • When extending an ORAData class, the subclass also implements the ORADataFactory interface, with an implementation of the ORADataFactory create() method such as the following.

    public ORAData create(Datum d, int sqlType) throws SQLException
    {
       return create(new UserClass(),d,sqlType);
    }
    
    

    When the class is part of an inheritance hierarchy, however, the generated method changes to protected ORAData createExact(), with the same signature and body as create().

JPublisher-Generated Subclasses for Java-to-Java Type Transformations

JPublisher style files, described in "JPublisher Styles and Style Files", enable you to specify Java-to-Java type mappings. A typical use for such mappings is to ensure that generated classes can be used in Web services. As a particular example, CLOB types such as java.sql.Clob and oracle.sql.CLOB cannot be used in Web services. However, the data can be used if converted to a type, such as java.lang.String, that is supported by Web services.

If you use the JPublisher -style option to specify a style file, JPublisher generates subclasses that implement the Java-to-Java type mappings specified in the style file. This includes the use of "holder" classes, introduced in "Passing Output Parameters in JAX-RPC Holders", for handling output arguments—data corresponding to PL/SQL OUT or IN OUT types.

For example, consider the following PL/SQL package, foo_pack, consisting of the stored function foo:

create or replace package foo_pack as 
   function foo(a IN OUT sys.xmltype, b integer) return CLOB; 
end; 
/

Assume that you translate the foo_pack package as follows:

% jpub -u scott/tiger -s foo_pack:FooPack -style=webservices10

This command uses the style file webservices10.properties for Java-to-Java type mappings. (This style file is supplied by Oracle and is typically appropriate for using Web services in an Oracle Database 10g environment.) The webservices10.properties file specifies the following (among other things):

  • The mapping of the Java type oracle.sql.SimpleXMLType (which is not supported by Web services) to the Java type javax.xml.transform.Source (which is):

    SOURCETYPE oracle.sql.SimpleXMLType
    TARGETTYPE javax.xml.transform.Source
    ...
    
    
  • The use of holder classes for PL/SQL OUT and IN OUT arguments:

    jpub.outarguments=holder
    
    

    This setting directs JPublisher to use instances of the appropriate holder class, in this case javax.xml.rpc.holders.SourceHolder, for the PL/SQL output argument of type XMLTYPE.

  • The inclusion of webservices-common.properties:

    INCLUDE webservices-common
    
    

The webservices-common.properties file (also supplied by Oracle) specifies the following:

  • The mapping of SYS.XMLTYPE to oracle.sql.SimpleXMLType in the JPublisher default type map:

    jpub.adddefaulttypemap=SYS.XMLTYPE:oracle.sql.SimpleXMLType
    
    
  • A code generation naming pattern:

    jpub.genpattern=%2Base:%2User#%2
    
    

    Based on the "-s foo_pack:FooPack" specification to JPublisher, the genpattern setting results in generation of the interface FooPack, the base class FooPackBase, and the user subclass FooPackUser, which extends FooPackBase and implements FooPack. See "Class and Interface Naming Pattern (-genpattern)" for general information about the -genpattern option.

  • The mapping of the Java type oracle.sql.CLOB (which is not supported by Web services) to the Java type java.lang.String (which is):

    SOURCETYPE oracle.sql.CLOB
    TARGETTYPE java.lang.String
    ...
    
    

Recall the calling sequence for the foo stored function:

function foo(a IN OUT sys.xmltype, b integer) return CLOB;

The base class generated by JPublisher, FooPackBase, has the following corresponding method declaration:

public oracle.sql.CLOB _foo (oracle.sql.SimpleXMLType a[], Integer b);

The base class uses an array to support the output argument. (See "Passing Output Parameters in Arrays".)

The user subclass has the following corresponding method declaration:

public java.lang.String foo (SourceHolder _xa_inout_x, Integer b);

This is because of the specified mapping of oracle.sql.SimpleXMLType to javax.xml.transform.Source, the specified use of holder classes for output arguments, and the specified mapping of oracle.sql.CLOB to java.lang.String (all as described earlier).

Following is the class SourceHolder, the holder class for Source:

// Holder class for javax.xml.transform.Source 
public class SourceHolder implements javax.xml.rpc.holders.Holder 
{ 
   public javax.xml.transform.Source value; 
   public SourceHolder() { } 
   public SourceHolder(javax.xml.transform.Source value) 
   { this.value = value; } 
}

Generated user subclasses employ the following general functionality for Java-to-Java type transformations in the wrapper method:

User subclass method 
{
     Enter Holder layer (extract IN data from the holder) 
          Enter Java-to-Java mapping layer (from target to source) 
               Call base class method (uses JDBC to invoke wrapped procedure) 
          Exit Java-to-Java mapping layer (from source to target) 
     Exit Holder layer (update the holder)
}

For the example, this is as follows in the foo() method of the class FooPackUser:

foo (SourceHolder, Integer)
{
     SourceHolder -> Source 
          Source -> SimpleXMLType 
               _foo (SimpleXMLType[], Integer); 
          SimpleXMLType -> Source 
     Source -> SourceHolder
}


Note:

Do not confuse the term "source" with the class name Source. In this example, Source is a target type and SimpleXMLType is the corresponding source type.

The holder layer retrieves and assigns the holder instance.

In the example, the holder layer in foo() performs the following:

  1. It retrieves a Source object from the SourceHolder object that is passed in to the foo() method (data input).

  2. After processing (which occurs inside the type conversion layer), it assigns the SourceHolder object from the Source object that was retrieved and processed (data output).

The type conversion layer first takes the target type (TARGETTYPE from the style file), next converts it to the source type (SOURCETYPE from the style file), then calls the corresponding method in the base class (which uses JDBC to invoke the wrapped stored function), and finally converts the source type returned by the base class method back into the target type to return to the holder layer.

In this example, the type conversion layer in foo() performs the following:

  1. It takes the Source object from the holder layer (data input).

  2. It converts the Source object to a SimpleXMLType object.

  3. It passes the SimpleXMLType object to the _foo() method of the base class, which uses JDBC to invoke the foo stored function.

  4. It takes the SimpleXMLType object returned by the _foo() method (output from the foo stored function).

  5. It converts the SimpleXMLType object back to a Source object for the holder layer (data output).

JPublisher Support for Inheritance

This section primarily discusses inheritance support for ORAData types, explaining the following related topics:

Following this information is a brief overview of standard inheritance support for SQLData types, with reference to appropriate documentation for further information.

ORAData Object Types and Inheritance

Consider the following SQL object types:

CREATE TYPE PERSON AS OBJECT (
...
) NOT FINAL;

CREATE TYPE STUDENT UNDER PERSON (
...
);

CREATE TYPE INSTRUCTOR UNDER PERSON (
...
);

And consider the following JPublisher command line to create corresponding Java classes (a single wraparound command):

% jpub -user=scott/tiger
       -sql=PERSON:Person,STUDENT:Student,INSTRUCTOR:Instructor -usertypes=oracle

In this example, JPublisher generates a Person class, a Student class, and an Instructor class. The Student and Instructor classes extend the Person class, because STUDENT and INSTRUCTOR are subtypes of PERSON.

The class at the root of the inheritance hierarchy, Person in this example, contains the full information for the entire inheritance hierarchy and automatically initializes its type map with the required information. As long as you use JPublisher to generate all the required classes of a class hierarchy together, no additional action is required. The type map of the class hierarchy is appropriately populated.

Precautions when Combining Partially Generated Type Hierarchies

If you run JPublisher several times on a SQL type hierarchy, each time generating only part of the corresponding Java wrapper classes, then you must take precautions in the user application to ensure that the type map at the root of the class hierarchy is properly initialized.

In our previous example, you may have run the following JPublisher commands:

% jpub -user=scott/tiger -sql=PERSON:Person,STUDENT:Student -usertypes=oracle
% jpub -user=scott/tiger -sql=PERSON:Person,INSTRUCTOR:Instructor
       -usertypes=oracle

In this case, you should create instances of the generated classes—at a minimum, the leaf classes—before using these mapped types in your code. For example:

new Instructor(); // required
new Student();    // required
new Person();     // optional

The reason for this requirement is explained next.

Mapping of Type Hierarchies in JPublisher-Generated Code

The Person class includes the following method:

Person create(oracle.sql.Datum d, int sqlType)

This method, which converts a Datum instance to its representation as a custom Java object, is called by the Oracle JDBC driver whenever a SQL object declared to be a PERSON is retrieved into a Person variable. The SQL object, however, may actually be a STUDENT object. In this case, the create() method must create a Student instance rather than a Person instance.

To handle this kind of situation, the create() method of a custom Java class (whether or not the class was created by JPublisher) must be able to create instances of any subclass that represents a subtype of the SQL object type corresponding to the oracle.sql.Datum argument. This ensures that the actual type of the created Java object matches the actual type of the SQL object.

The code for the create() method in the root class of a custom Java class hierarchy need not mention the subclasses, however. In fact, if it did mention the subclasses, you would have to modify the code for the base class whenever you write or create a new subclass. The base class is modified automatically if you use JPublisher to regenerate the entire class hierarchy, but regenerating the hierarchy may not always be possible. For example, you may not have access to the source code for the Java classes being extended.

Instead, code generated by JPublisher permits incremental extension of a class hierarchy by creating a static initialization block in each subclass of the custom Java class hierarchy. This static initialization block initializes a data structure (equivalent to a type map) declared in the root-level Java class, giving the root class the information it needs about the subclass. When an instance of a subclass is created at runtime, the type is registered in the data structure. Because of this implicit mapping mechanism, no explicit type map, such as those required in SQLData scenarios, is required.


Important:

This implementation makes it possible to extend existing classes without having to modify them, but it also carries a penalty. The static initialization blocks of the subclasses must be executed before the class hierarchy can be used to read objects from the database. This occurs if you instantiate an object of each subclass by calling new(). It is sufficient to instantiate just the leaf classes, because the constructor for a subclass invokes the constructor for its immediate superclass.

As an alternative, you can generate (or regenerate) the entire class hierarchy, if feasible.


ORAData Reference Types and Inheritance

This section shows how to convert from one custom reference class to another, and also explains why a custom reference class generated for a subtype by JPublisher does not extend the reference classes of the base type.

Casting a Reference Type Instance into Another Reference Type

Revisiting the example in "ORAData Object Types and Inheritance", PersonRef, StudentRef, and InstructorRef are obtained for strongly typed references, in addition to the underlying object type wrapper classes.

There may be situations in which you have a StudentRef instance, but you want to use it in a context that requires a PersonRef instance. In this case, use the static cast() method generated in strongly typed reference classes:

StudentRef s_ref = ...;  
PersonRef p_ref = PersonRef.cast(s_ref);

Conversely, you may have a PersonRef instance and know that you can narrow it to an InstructorRef instance:

PersonRef pr = ...; 
InstructorRef ir = InstructorRef.cast(pr);

Why Reference Type Inheritance Does Not Follow Object Type Inheritance

The example here helps explain why it is not desirable for reference types to follow the hierarchy of their related object types.

Consider again a subset of the example given in the previous section, repeated here for convenience:

CREATE TYPE PERSON AS OBJECT (
...
) NOT FINAL;

CREATE TYPE STUDENT UNDER PERSON (
...
);

And consider the following JPublisher command:

% jpub -user=scott/tiger -sql=PERSON:Person,STUDENT:Student -usertypes=oracle

In addition to generating the Person and Student Java types, JPublisher generates PersonRef and StudentRef types.

Because the Student class extends the Person class, you may expect StudentRef to extend PersonRef. This is not the case, however, because the StudentRef class can provide more compile-time type safety as an independent class than as a subtype of PersonRef. Additionally, a PersonRef object can perform something that a StudentRef object cannot: modifying a Person object in the database.

The most important methods of the PersonRef class are the following:

  • Person getValue()

  • void setValue(Person c)

The corresponding methods of the StudentRef class are as follows:

  • Student getValue()

  • void setValue(Student c)

If the StudentRef class extended the PersonRef class, two problems would occur:

  • Java would not permit the getValue() method in StudentRef to return a Student object when the method it would override in the PersonRef class returns a Person object, even though this is arguably a sensible thing to do.

  • The setValue() method in StudentRef would not override the setValue() method in PersonRef, because the two methods have different signatures.

It would not be sensible to remedy these problems by giving the StudentRef methods the same signatures and result types as the PersonRef methods, because the additional type safety provided by declaring an object as a StudentRef, rather than as a PersonRef, would be lost.

Manually Converting Between Reference Types

Because reference types do not follow the hierarchy of their related object types, there is a JPublisher limitation that you cannot convert directly from one reference type to another. For background information, this section explains how the generated cast() methods work to convert from one reference type to another.

It is not recommended that you follow these manual steps. They are presented here for illustration only. You can use the cast() method instead.

The following example outlines code that could be used to convert from the reference type XxxxRef to the reference type YyyyRef:

java.sql.Connection conn = ...;  // get underlying JDBC connection
XxxxRef xref = ...;
YyyyRef yref = (YyyyRef) YyyyRef.getORADataFactory().
                create(xref.toDatum(conn), Oracle.jdbc.OracleTypes.REF);

This conversion consists of two steps, each of which can be useful in its own right.

  1. Convert xref from its strong XxxxRef type to the weak oracle.sql.REF type:

    oracle.sql.REF ref  = (oracle.sql.REF) xref.toDatum(conn);
    
    
  2. Convert from the oracle.sql.REF type to the target YyyyRef type:

    YyyyRef yref = (YyyyRef) YyyyRef.getORADataFactory().
                              create(ref, Oracle.jdbc.OracleTypes.REF);
    
    

"Example: Manually Converting Between Reference Types", which immediately follows, provides sample code for such a conversion.


Note:

This conversion does not include any type-checking. Whether this conversion is actually permitted depends on your application and on the SQL schema you are using.

Example: Manually Converting Between Reference Types

The following example, including SQL definitions and Java code, illustrates the points of the preceding discussion.


SQL Definitions

Consider the following SQL definitions:

create type person_t as object (ssn number, name varchar2 (30), dob date) not
final;
/
show errors

create type instructor_t under person_t (title varchar2(20)) not final;
/
show errors

create type instructorPartTime_t under instructor_t (num_hours number);
/
show errors

create type student_t under person_t (deptid number, major varchar2(30)) not
final;
/
show errors

create type graduate_t under student_t (advisor instructor_t);
/
show errors

create type studentPartTime_t under student_t (num_hours number);
/
show errors

create table person_tab  of person_t;

insert into person_tab values (1001, 'Larry', TO_DATE('11-SEP-60'));
insert into person_tab values (instructor_t(1101, 'Smith', TO_DATE
('09-OCT-1940'), 'Professor'));
insert into person_tab values (instructorPartTime_t(1111, 'Myers',
TO_DATE('10-OCT-65'), 'Adjunct Professor', 20));
insert into person_tab values (student_t(1201, 'John', To_DATE('01-OCT-78'), 11,
'EE'));
insert into person_tab values (graduate_t(1211, 'Lisa', TO_DATE('10-OCT-75'),
12, 'ICS', instructor_t(1101, 'Smith', TO_DATE ('09-OCT-40'), 'Professor')));
insert into person_tab values (studentPartTime_t(1221, 'Dave',
TO_DATE('11-OCT-70'), 13, 'MATH', 20));

JPublisher Mappings

Assume the following mappings when you run JPublisher:

Person_t:Person,instructor_t:Instructor,instructorPartTime_t:InstructorPartTime,
graduate_t:Graduate,studentPartTime_t:StudentPartTime

SQLJ Class

Here is a SQLJ class with an example of reference type conversion as discussed earlier, in "Manually Converting Between Reference Types":

import java.sql.*; 
import oracle.jdbc.*; 
import oracle.sql.*; 

public class Inheritance 
{ 
  public static void main(String[] args) throws SQLException 
  { 
    System.out.println("Connecting."); 
    java.sql.DriverManager.registerDriver(new oracle.jdbc.OracleDriver()); 
    oracle.jdbc.OracleConnection conn = 
              (oracle.jdbc.OracleConnection) java.sql.DriverManager.getConnection
              ("jdbc:oracle:oci8:@", "scott", "tiger");
    // The following is only required in 9.0.1 
    // or if the Java class hierarchy was created piecemeal 
    System.out.println("Initializing type system."); 
    new Person(); 
    new Instructor(); 
    new InstructorPartTime(); 
    new StudentT(); 
    new StudentPartTime(); 
    new Graduate(); 
    PersonRef p_ref; 
    InstructorRef i_ref; 
    InstructorPartTimeRef ipt_ref; 
    StudentTRef s_ref; 
    StudentPartTimeRef spt_ref; 
    GraduateRef g_ref; 
    OraclePreparedStatement stmt =
                (OraclePreparedStatement)conn.prepareStatement
                ("select ref(p) FROM PERSON_TAB p WHERE p.NAME=:1"); 
    OracleResultSet rs; 

    System.out.println("Selecting a person."); 
    stmt.setString(1, "Larry"); 
    rs = (OracleResultSet) stmt.executeQuery(); 
    rs.next(); 
    p_ref = (PersonRef) rs.getORAData(1, PersonRef.getORADataFactory()); 
    rs.close(); 

    System.out.println("Selecting an instructor."); 
    stmt.setString(1, "Smith"); 
    rs = (OracleResultSet) stmt.executeQuery(); 
    rs.next(); 
    i_ref = (InstructorRef) rs.getORAData(1, InstructorRef.getORADataFactory()); 
    rs.close(); 

    System.out.println("Selecting a part time instructor."); 
    stmt.setString(1, "Myers"); 
    rs = (OracleResultSet) stmt.executeQuery(); 
    rs.next(); 
    ipt_ref = (InstructorPartTimeRef) rs.getORAData
              (1, InstructorPartTimeRef.getORADataFactory()); 
    rs.close(); 

    System.out.println("Selecting a student."); 
    stmt.setString(1, "John"); 
    rs = (OracleResultSet) stmt.executeQuery(); 
    rs.next(); 
    s_ref = (StudentTRef) rs.getORAData(1, StudentTRef.getORADataFactory()); 
    rs.close(); 

    System.out.println("Selecting a part time student."); 
    stmt.setString(1, "Dave"); 
    rs = (OracleResultSet) stmt.executeQuery(); 
    rs.next(); 
    spt_ref = (StudentPartTimeRef) rs.getORAData
              (1, StudentPartTimeRef.getORADataFactory()); 
    rs.close(); 

    System.out.println("Selecting a graduate student."); 
    stmt.setString(1, "Lisa"); 
    rs = (OracleResultSet) stmt.executeQuery(); 
    rs.next(); 
    g_ref = (GraduateRef) rs.getORAData(1, GraduateRef.getORADataFactory()); 
    rs.close(); 
    stmt.close(); 

    // Assigning a part-time instructor ref to a person ref 
    System.out.println("Assigning a part-time instructor ref to a person ref"); 
    oracle.sql.Datum ref = ipt_ref.toDatum(conn); 
    PersonRef pref = (PersonRef) PersonRef.getORADataFactory(). 
                                           create(ref,OracleTypes.REF); 
    // or just use: PersonRef pref = PersonRef.cast(ipt_ref); 
    // Assigning a person ref to an instructor ref 
    System.out.println("Assigning a person ref to an instructor ref"); 
    InstructorRef iref = (InstructorRef) InstructorRef.getORADataFactory(). 
                                     create(pref.toDatum(conn), OracleTypes.REF); 
    // or just use: InstructorRef iref = InstructorRef.cast(pref); 
    // Assigning a graduate ref to an part time instructor ref. 
    // This should produce an error, demonstrating that refs 
    // are type safe. 
    System.out.println ("Assigning a graduate ref to a part time instructor ref"); 
    InstructorPartTimeRef iptref = 
                (InstructorPartTimeRef) InstructorPartTimeRef.getORADataFactory(). 
                create(g_ref.toDatum(conn), OracleTypes.REF); 
    // or just use: InstructorPartTimeRef iptref = 
    // InstructorPartTimeRef.cast(g_ref); 
    conn.close(); 
  } 
} 

SQLData Object Types and Inheritance

If you use the JPublisher -usertypes=jdbc setting instead of -usertypes=oracle, then the custom Java class generated by JPublisher implements the standard SQLData interface instead of the Oracle ORAData interface. The SQLData standard readSQL() and writeSQL() methods provide equivalent functionality to the ORAData/ORADataFactory create() and toDatum() methods for reading and writing data.

As is the case when JPublisher generates ORAData classes corresponding to a hierarchy of SQL object types, when JPublisher generates SQLData classes corresponding to a SQL hierarchy, the Java types follow the same hierarchy as the SQL types.

SQLData implementations do not, however, offer the implicit mapping intelligence that JPublisher automatically generates in ORAData classes (as described in "ORAData Object Types and Inheritance").

In a SQLData scenario, you must manually provide a type map to ensure the proper mapping between SQL object types and Java types. In a JDBC application, you can properly initialize the default type map for your connection, or you can explicitly provide a type map as a getObject() input parameter. See the Oracle Database JDBC Developer's Guide and Reference for information.

In addition, note that there is no support for strongly typed object references in a SQLData implementation. All object references are weakly typed java.sql.Ref instances.

Effects of Using SQL FINAL, NOT FINAL, NOT INSTANTIABLE

This section discusses the effect on JPublisher-generated wrapper classes of using the SQL modifiers FINAL, NOT FINAL, or NOT INSTANTIABLE.

Using the SQL modifier FINAL or NOT FINAL on a SQL type or on a method of a SQL type has no effect on the generated Java wrapper code. This is so JPublisher users are able in all cases to customize generated Java wrapper classes by extending the classes and overriding the generated behavior.

Using the SQL modifier NOT INSTANTIABLE on a method of a SQL type results in no code being generated for that method in the Java wrapper class. Therefore, to call such a method, you must cast to some wrapper class that corresponds to an instantiable SQL subtype.

Using NOT INSTANTIABLE on a SQL type results in the corresponding wrapper class being generated with protected constructors. This will remind you that instances of that class can be created only through subclasses that correspond to instantiable SQL types.