Oracle9i JPublisher User's Guide
Release 1 (9.0.1)

Part Number A90214-01
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback

Go to previous page Go to next page

1
Understanding and Using JPublisher

This chapter provides an overview of JPublisher followed by more detailed discussion of its operation. The following topics are covered:

Understanding JPublisher

This section provides a basic understanding of what JPublisher is for and what it accomplishes, covering the following topics:

Introduction to JPublisher

JPublisher is a utility, written entirely in Java, that generates Java classes to represent the following user-defined database entities in your Java program:

JPublisher enables you to specify and customize the mapping of SQL object types, object reference types, and collection types (VARRAYs or nested tables) to Java classes in a strongly typed paradigm.

JPublisher generates getXXX() and setXXX() accessor methods for each attribute of an object type. If your object types have stored procedures, JPublisher can generate wrapper methods to invoke the stored procedures. A wrapper method is a method that invokes a stored procedure that executes in Oracle9i.

JPublisher can also generate classes for PL/SQL packages. These classes have wrapper methods to invoke the stored procedures in the PL/SQL packages.

The wrapper methods JPublisher generates contain SQLJ code, so when JPublisher generates wrapper methods, it generally produces .sqlj source files. This is true for classes representing PL/SQL packages or object types that define methods, unless you specify (through the -methods option) that JPublisher should not generate wrapper methods.

If no wrapper methods are generated, JPublisher produces .java source files. This is true for classes representing object types without methods, object reference types, or collection types, or for classes where the -methods option is off.

Instead of using JPublisher-generated classes directly, you can:

Object Types and JPublisher

JPublisher allows your Java language applications to employ user-defined object types in Oracle9i. If you intend to have your Java-language application access object data, then it must represent the data in a Java format. JPublisher helps you do this by creating the mapping between object types and Java classes, and between object attribute types and their corresponding Java types.

Classes generated by JPublisher implement either the oracle.sql.ORAData interface or the java.sql.SQLData interface, depending on how you set the JPublisher options. Either interface makes it possible to transfer object type instances between the database (or middle-tier database cache) and your Java program. For more information about the ORAData and SQLData interfaces, see the Oracle9i JDBC Developer's Guide and Reference.

PL/SQL Packages and JPublisher

You might want to call stored procedures in a PL/SQL package from your Java application. The stored procedure can be a PL/SQL subprogram or a Java method that has been published to SQL. Java arguments and functions are passed to and returned from the stored procedure.

To help you do this, you can direct JPublisher to create a class containing a wrapper method for each subprogram in the package. The wrapper methods generated by JPublisher provide a convenient way to invoke PL/SQL stored procedures from Java code or to invoke a Java stored procedure from a client Java program.

If you call PL/SQL code that includes top-level subprograms (subprograms not in any PL/SQL package), JPublisher generates a single class containing wrapper methods for the top-level subprograms you request.

What JPublisher Does

JPublisher connects to a database and retrieves descriptions of the SQL object types or PL/SQL packages that you specify on the command line or from an input file. By default, JPublisher connects to the database by using the JDBC OCI driver, which requires an Oracle client installation, including Oracle Net and required support files. If you do not have an Oracle client installation, JPublisher can use the Oracle JDBC Thin driver.

JPublisher generates a Java class for each SQL object type it translates. The Java class includes code required to read objects from and write objects to the database. When you deploy the generated JPublisher classes, your JDBC driver installation includes all the necessary runtime files. If you create wrapper methods (Java methods to wrap stored procedures or functions of the SQL object type), JPublisher generates SQLJ source code so you must additionally have the SQLJ runtime libraries.

When you call a wrapper method, the SQL value for the object is sent to the server, along with any IN our IN OUT arguments. Then the method (stored procedure or function) is invoked, and the new object value is returned to the client, along with any OUT or IN OUT arguments.

JPublisher also generates a class for each PL/SQL package it translates. The class includes code to invoke the package methods on the server. IN arguments for the methods are transmitted from the client to the server, and OUT arguments and results are returned from the server to the client.

The next section furnishes a general description of the source files that JPublisher creates for object types and PL/SQL packages.

What JPublisher Produces

The number of files JPublisher produces depends on whether you request ORAData classes (classes that implement the oracle.sql.ORAData interface) or SQLData classes (classes that implement the standard java.sql.SQLData interface).

The ORAData interface supports SQL object, object reference, and collection types in a strongly typed way. That is, for each specific object, object reference, or collection type in the database, there is a corresponding Java type. The SQLData interface, on the other hand, supports only SQL object types in a strongly typed way. All object reference types are represented generically as java.sql.Ref instances, and all collection types are represented generically as java.sql.Array instances. Therefore, JPublisher generates classes for object reference and collection types only if it is generating ORAData classes.

When you run JPublisher for a user-defined object type and you request ORAData classes, JPublisher automatically creates the following:

If, instead, you request SQLData classes, JPublisher does not generate the object reference class and does not generate classes for nested collection attributes.

When you run JPublisher for a user-defined collection type, you must request ORAData classes. JPublisher automatically creates the following:

When you run JPublisher for a PL/SQL package, it automatically creates the following:

JPublisher Requirements

JPublisher requires that Oracle SQLJ and Oracle JDBC also be installed on your system and in your classpath appropriately. You will need the following libraries (all available as either .zip or .jar):

"12" refers to versions for JDK 1.2.x; "11" and "111" refer to versions for JDK 1.1.x. See the Oracle9i SQLJ Developer's Guide and Reference for more information about these files.

When you use Oracle9i JPublisher, you should also use the equivalent version of SQLJ, because these two products are always installed together. To use all features of JPublisher, you also need:

If you are using only some features of JPublisher, your requirements might be less stringent:

JPublisher Input and Output

You can specify input options on the command line and in the properties file. In addition to producing .sqlj and .java files for the translated objects, JPublisher writes the names of the translated objects and packages to standard output.

JPublisher Input

You can specify JPublisher options on the command line or in a properties file. "JPublisher Options" describes all the JPublisher options.

In addition, you can use a file known as the INPUT file to specify the object types and PL/SQL packages JPublisher should translate. It also controls the naming of the generated packages and classes. "INPUT File Structure and Syntax" describes INPUT file syntax.

A properties file is an optional text file that you can use to specify frequently-used options. You name the properties file on the command line. JPublisher processes the properties file as if its contents were inserted, in sequence, on the command line at that point. For more information about this file, see "Properties File Structure and Syntax".

JPublisher Output

JPublisher generates a Java class for each object type that it translates. For each object type, JPublisher generates a <type>.sqlj file (or a <type>.java file if wrapper methods were suppressed or do not exist) for the class code and a <type>Ref.java file for the code for the REF class of the Java type. For example, if you define an EMPLOYEE SQL object type, JPublisher generates an employee.sqlj file (or an employee.java file) and an employeeRef.java file. Note that the case of Java class names produced by JPublisher is determined by the -case option. See "Case of Java Identifiers (-case)".

For each collection type (nested table or VARRAY) it translates, JPublisher generates a <type>.java file. For nested tables, the generated class has methods to get and set the nested table as an entire array and to get and set individual elements of the table. JPublisher translates collection types when generating ORAData classes, but not when generating SQLData classes.

For PL/SQL packages, JPublisher generates classes containing wrapper methods as .sqlj files.

When JPublisher generates the class files and wrappers, it also writes the names of the translated types and packages to standard output.

Overview of Datatype Mappings

JPublisher offers different categories of datatype mappings from SQL to Java. JPublisher options to specify these mappings are described below, under "Detailed Descriptions--Options That Affect Datatype Mappings".

Each type mapping option has at least two possible values: jdbc and oracle. The -numbertypes option has two additional alternatives: objectjdbc and bigdecimal.

The following sections describe these categories of mappings.

For more information about datatype mappings, see "Details of Datatype Mapping".

JDBC Mapping

The JDBC mapping maps most numeric datatypes to Java primitive types such as int and float, and maps DECIMAL and NUMBER to java.math.BigDecimal. LOB types and other non-numeric built-in types map to standard JDBC Java types such as java.sql.Blob and java.sql.Timestamp. For object types, JPublisher generates SQLData classes. Predefined datatypes that are Oracle extensions (such as BFILE and ROWID) do not have JDBC mappings, so only the oracle.sql.* mapping is supported for these types.

The Java primitive types used in the JDBC mapping do not support null values and do not guard against integer overflow or floating-point loss of precision. If you are using the JDBC mapping and you attempt to call an accessor or method to get an attribute of a primitive type (short, int, float, or double) whose value is null, an exception is thrown. If the primitive type is short or int, then an exception is thrown if the value is too large to fit in a short or int variable.

Object JDBC Mapping

The Object JDBC mapping maps most numeric datatypes to Java wrapper classes such as java.lang.Integer and java.lang.Float, and maps DECIMAL and NUMBER to java.math.BigDecimal. It differs from the JDBC mapping only in that it does not use primitive types.

When you use the Object JDBC mapping, all your returned values are objects. If you attempt to get an attribute whose value is null, a null object is returned.

The Java wrapper classes used in the Object JDBC mapping do not guard against integer overflow or floating-point loss of precision. If you call an accessor method to get an attribute that maps to java.lang.Integer, an exception is thrown if the value is too large to fit.

This is the default mapping for numeric types.

BigDecimal Mapping

BigDecimal mapping, as the name implies, maps all numeric datatypes to java.math.BigDecimal. It supports null values and very large values.

Oracle Mapping

In the Oracle mapping, JPublisher maps any numeric, LOB, or other built-in type to a class in the oracle.sql package. For example, the DATE type is mapped to oracle.sql.DATE, and all numeric types are mapped to oracle.sql.NUMBER. For object, collection, and object reference types, JPublisher generates ORAData classes.

Because the Oracle mapping uses no primitive types, it can represent a null value as a Java null in all cases. Because it uses the oracle.sql.NUMBER class for all numeric types, it can represent the largest numeric values that can be stored in the database.

Creating Types and Packages in the Database

Before you run JPublisher, you must create any new datatypes that you will require in the database. You must also ensure that any PL/SQL packages, methods, and subprograms that you want to invoke from Java are also installed in Oracle9i.

Use the SQL CREATE TYPE statement to create object, VARRAY, and nested table types in the database. JPublisher supports the mapping of these datatypes to Java classes. JPublisher also generates classes for references to object types. REF types are not explicitly declared in SQL. For more information on creating object types, see the Oracle9i SQL Reference.

Use the CREATE PACKAGE and CREATE PACKAGE BODY statements to create PL/SQL packages and store them in the database. PL/SQL furnishes all the capabilities necessary to implement the methods associated with object types. These methods (functions and procedures) reside on the server as part of a user's schema. You can implement the methods in PL/SQL or Java.

Packages are often implemented to provide the following advantages:

For more information on PL/SQL and creating PL/SQL packages, see the PL/SQL User's Guide and Reference.

JPublisher Operation

This section discusses the basic steps in using JPublisher, describes the command-line syntax, and concludes with a sample translation. The following topics are covered:

Translating and Using PL/SQL Packages and User-Defined Types

Here are the basic steps for translating and using code for user-defined types and PL/SQL packages. (User-defined types include Oracle objects and Oracle collections--VARRAYs and nested tables.)

  1. Create the desired user-defined datatypes and PL/SQL packages in the database.

  2. JPublisher generates source code for Java classes that represent PL/SQL packages, user-defined types, and reference types and places them in specified Java packages. JPublisher generates .java files for object reference, VARRAY, and nested table classes. If you instruct JPublisher to generate wrapper methods, it will generate .sqlj files for packages and object types (assuming the object types have methods). If you instruct JPublisher to not generate wrapper methods, it will generate .java files without wrapper methods for object types and will not generate classes for packages (because they contain only wrapper methods). For object types without methods, JPublisher generates .java files in any case.

  3. Import these classes into your application code.

  4. Use the methods in the generated classes to access and manipulate the user-defined types and their attributes.

  5. Compile all classes (the JPublisher-generated code and your code). SQLJ translates the .sqlj files, and the Java compiler compiles the .java files.

  6. Run your compiled application.

Figure 1-1 illustrates the preceding steps.

Figure 1-1 Translating and Using Object Code


Text description of transobj.jpg follows.
Text description of the illustration transobj.jpg

Representing User-Defined Object, Collection, and Reference Types in Java

Here are the three ways to represent user-defined object, collection, and object reference types in your Java program:

Compared to classes that implement SQLData, classes that implement ORAData are fundamentally more efficient, because ORAData classes avoid unnecessary conversions to native Java types. For a comparison of the SQLData and ORAData interfaces, see the Oracle9i JDBC Developer's Guide and Reference.

Compared to oracle.sql.* classes, classes that implement ORAData or SQLData are strongly typed. Your connected SQLJ translator will detect an error at translation time if, for example, you mistakenly select a PERSON object into an ORAData object that represents an ADDRESS.

JPublisher-generated classes that implement ORAData or SQLData have additional advantages:

Strongly Typed Object References for ORAData Implementations

For Oracle ORAData implementations, JPublisher always generates strongly typed object reference classes as opposed to using the weakly typed oracle.sql.REF class. This is to provide greater type safety and to mirror the behavior in SQL, where object references are strongly typed. The strongly typed classes (with names such as PersonRef for references to PERSON objects) are essentially wrappers for the REF class.

In these strongly typed REF wrappers, there is a getValue() method that produces an instance of the SQL object that is referenced, in the form of an instance of the corresponding Java class. (Or, in the case of inheritance, perhaps as an instance of a subclass of the corresponding Java class.) For example, if there is a PERSON object type in the database, with a corresponding Person Java class, there will also be a PersonRef Java class. The getValue() method of the PersonRef class would return a Person instance containing the data for a PERSON object in the database.

Whenever a SQL object type has an attribute that is an object reference, the Java class corresponding to the object type would have an attribute that is an instance of a Java class corresponding to the appropriate reference type. For example, if there is a PERSON object with a MANAGER REF attribute, then the corresponding Person Java class will have a ManagerRef attribute.

For standard SQLData implementations, strongly typed object references are not supported--they are not part of the standard. JPublisher does not create a custom reference class; you must use java.sql.Ref or oracle.sql.REF as the reference type.

JPublisher Command-Line Syntax

On most operating systems, you invoke JPublisher on the command line, typing jpub followed by a series of options settings as follows:

jpub -option1=value1 -option2=value2 ...

JPublisher responds by connecting to the database and obtaining the declarations of the types or packages you specify, then generating one or more custom Java files and writing the names of the translated object types or PL/SQL packages to standard output.

Here is an example of a command that invokes JPublisher (this is a single wrap-around command line):

jpub -user=scott/tiger -input=demoin -numbertypes=oracle -usertypes=oracle 
-dir=demo -package=corp

You enter the command on one line, allowing it to wrap as necessary. For clarity, this chapter refers to the input file (the file specified by the -input option) as the INPUT file (to distinguish it from any other kinds of input files).

This command directs JPublisher to connect to the database with username SCOTT and password TIGER and translate datatypes to Java classes, based on instructions in the INPUT file demoin. The -numbertypes=oracle option directs JPublisher to map object attribute types to Java classes supplied by Oracle, and the -usertypes=oracle option directs JPublisher to generate Oracle-specific ORAData classes. JPublisher places the classes that it generates in the package corp in the directory demo.

"JPublisher Options" describes each of these options in more detail.


Notes:

  • No spaces are permitted around the equals sign (=).

  • If you execute JPublisher without any options on the command line, it displays an option list and then terminates.

 

Sample JPublisher Translation

This section provides a sample JPublisher translation of an object type. At this point, do not worry about the details of the code JPublisher generates. You can find more information about JPublisher input and output files, options, datatype mappings, and translation later in this manual.

Create the object type EMPLOYEE:

CREATE TYPE employee AS OBJECT
(
    name       VARCHAR2(30),
    empno      INTEGER,
    deptno     NUMBER,
    hiredate   DATE,
    salary     REAL
);

The INTEGER, NUMBER, and REAL types are all stored in the database as NUMBER types, but after translation they have different representations in the Java program, based on your choice for the value of the -numbertypes option.

JPublisher translates the types according to the following command line:

jpub -user=scott/tiger -dir=demo -numbertypes=objectjdbc -builtintypes=jdbc 
-package=corp -case=mixed -sql=Employee

(This is a single wrap-around command line.)

"JPublisher Options" describes each of these options in detail.

Note that because the EMPLOYEE object type does not define any methods, JPublisher will generate a .java file, not a .sqlj file.

Because -dir=demo and -package=corp were specified on the JPublisher command line, the translated class Employee is written to Employee.java in the following location:

./demo/corp/Employee.java           (UNIX)
.\demo\corp\Employee.java           (Windows NT)

The Employee.java class file would contain the code below.


Note:

The details of the code JPublisher generates are subject to change. In particular, non-public methods, non-public fields, and all method bodies may be generated differently. 


package corp;

import java.sql.SQLException;
import java.sql.Connection;
import oracle.jdbc.OracleTypes;
import oracle.sql.ORAData;
import oracle.sql.ORADataFactory;
import oracle.sql.Datum;
import oracle.sql.STRUCT;
import oracle.jpub.runtime.MutableStruct;

public class Employee implements ORAData, ORADataFactory
{
  public static final String _SQL_NAME = "SCOTT.EMPLOYEE";
  public static final int _SQL_TYPECODE = OracleTypes.STRUCT;

  protected MutableStruct _struct;

  static int[] _sqlType =
  {
    12, 4, 2, 91, 7
  };

  static ORADataFactory[] _factory = new ORADataFactory[5];

  static final Employee _EmployeeFactory = new Employee();
  public static ORADataFactory getORADataFactory()
  {
    return _EmployeeFactory;
  }

  /* constructor */
  protected Employee(boolean init)
  { if(init) _struct = new MutableStruct(new Object[5], _sqlType, _factory); }
  public Employee()
  { this(true); }

  /* ORAData interface */
  public Datum toDatum(Connection c) throws SQLException
  {
    return _struct.toDatum(c, _SQL_NAME);
  }

  /* ORADataFactory interface */
  public ORAData create(Datum d, int sqlType) throws SQLException
  { return create(null, d, sqlType); }
  protected ORAData create(Employee o, Datum d, int sqlType) throws SQLException
  {
    if (d == null) return null; 
    if (o == null) o = new Employee(false);
    o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory);
    return o;
  }

  /* accessor methods */
  public String getName() throws SQLException
  { return (String) _struct.getAttribute(0); }

  public void setName(String name) throws SQLException
  { _struct.setAttribute(0, name); }


  public Integer getEmpno() throws SQLException
  { return (Integer) _struct.getAttribute(1); }

  public void setEmpno(Integer empno) throws SQLException
  { _struct.setAttribute(1, empno); }


  public java.math.BigDecimal getDeptno() throws SQLException
  { return (java.math.BigDecimal) _struct.getAttribute(2); }

  public void setDeptno(java.math.BigDecimal deptno) throws SQLException
  { _struct.setAttribute(2, deptno); }


  public java.sql.Timestamp getHiredate() throws SQLException
  { return (java.sql.Timestamp) _struct.getAttribute(3); }

  public void setHiredate(java.sql.Timestamp hiredate) throws SQLException
  { _struct.setAttribute(3, hiredate); }


  public Float getSalary() throws SQLException
  { return (Float) _struct.getAttribute(4); }

  public void setSalary(Float salary) throws SQLException
  { _struct.setAttribute(4, salary); }

}

Code Generation Notes

JPublisher also generates an EmployeeRef.java class. The source code is displayed here:

package corp;

import java.sql.SQLException;
import java.sql.Connection;
import oracle.jdbc.OracleTypes;
import oracle.sql.ORAData;
import oracle.sql.ORADataFactory;
import oracle.sql.Datum;
import oracle.sql.REF;
import oracle.sql.STRUCT;

public class EmployeeRef implements ORAData, ORADataFactory
{
  public static final String _SQL_BASETYPE = "SCOTT.EMPLOYEE";
  public static final int _SQL_TYPECODE = OracleTypes.REF;

  REF _ref;

  static final EmployeeRef _EmployeeRefFactory = new EmployeeRef();
  public static ORADataFactory getORADataFactory()
  {
    return _EmployeeRefFactory;
  }

  /* constructor */
  public EmployeeRef()
  {
  }

  /* ORAData interface */
  public Datum toDatum(java.sql.Connection c) throws SQLException
  {
    return _ref;
  }

  /* ORADataFactory interface */
  public ORAData create(Datum d, int sqlType) throws SQLException
  {
    if (d == null) return null;
    EmployeeRef r = new EmployeeRef();
    r._ref = (REF) d;
    return r;
  }
  public Employee getValue() throws SQLException
  {
     return (Employee) Employee.getORADataFactory().create(
       _ref.getSTRUCT(), OracleTypes.REF);
  }

  public void setValue(Employee c) throws SQLException
  {
    _ref.setValue((STRUCT) c.toDatum(_ref.getJavaSqlConnection()));
  }
}

You can find more examples of object mappings in "Example: JPublisher Object Attribute Mapping".

Backwards Compatibility and Migration

This section discusses issues of backwards compatibility, compatibility between JDK versions, and migration between Oracle8i and Oracle9i releases of JPublisher.

JPublisher Backwards Compatibility

The JPublisher runtime is packaged with Oracle JDBC in the classes111 or classes12 library. Code generated by an earlier version of JPublisher will:

If you use an earlier release of the JPublisher runtime and Oracle JDBC in generating code, the code will be compilable against that version of the JPublisher runtime. Specifically, when you use an Oracle8i JDBC driver, JPublisher will generate code for the now-deprecated CustomDatum interface, not the ORAData interface that replaced it.

JPublisher Compatibility Between JDK Versions

Generally speaking, .sqlj files generated by JPublisher can be translated under either JDK 1.1.x (assuming you are not using JDBC 2.0-specific types) or JDK 1.2.x or higher. However, if you intend to translate and compile in separate steps (setting -compile=false in SQLJ so that only .java files, not .class files, are produced), then you must use the same JDK version for compilation as for translation unless you use a special JPublisher option setting.

In this situation (translating and compiling in separate steps), the JPublisher default setting -context=DefaultContext results in generation of .sqlj files that are completely compatible between JDK 1.1.x and JDK 1.2.x or higher. (With this setting, for example, you could translate against JDK 1.1.x but still compile against JDK 1.2.x successfully.)

In this situation, all generated .sqlj files use the sqlj.runtime.ref.DefaultContext class for all connection contexts. This is as opposed to the setting -context=generated, which results in each generated .sqlj file declaring its own connection context inner class. This was the Oracle8i JPublisher default behavior, and is what makes translated .java code incompatible between JDK 1.1.x and 1.2.x or higher.

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


Important:

With some JPublisher option settings under JDK 1.1.x there is risk of memory leakage caused by SQLJ connection context instances that are not closed. See "Releasing Connection Context Resources" for information. 


See the Oracle9i SQLJ Developer's Guide and Reference for general information about connection contexts.

Migration Between Oracle8i JPublisher and Oracle9i JPublisher

In Oracle9i JPublisher, default option settings and some features of the generated code have changed. If you wrote an application using JPublisher release 8.1.7 or earlier, it is unlikely that you will be able to simply re-run JPublisher in Oracle9i and have the generated classes still work within your application. This section describes how to modify your JPublisher option settings or your application code appropriately.


Note:

Also see "Changes in User-Written Subclasses of Oracle9i JPublisher-Generated Classes" for differences between Oracle8i functionality and Oracle9i functionality for classes that extend JPublisher-generated classes. 


Changes in Behavior in Oracle9i JPublisher

Be aware of the following changes in JPublisher behavior in Oracle9i:

See the following sections, "Individual Settings to Force JPublisher Behavior as in Previous Releases" and "Oracle8i Compatibility Mode", for information about how to revert to Oracle8i behavior instead.

Individual Settings to Force JPublisher Behavior as in Previous Releases

In Oracle9i, if you want JPublisher to behave as it did in release 8.1.7 and prior, there are a number of individual backwards-compatibility options you can set. These are detailed in Table 1-1. See descriptions of these options under "Detailed Descriptions--General JPublisher Options" for more information.

See "Oracle8i Compatibility Mode" for a single setting that results in the same behavior as for Oracle8i JPublisher--backwards-compatible code generation plus behavior that is equivalent to what would happen with the combination of these individual option settings.

Table 1-1 JPublisher Backwards-Compatibility Options
Option Setting  Behavior 

-context=generated 

This results in the declaration of an inner class, _Ctx, for SQLJ connection contexts. This is used instead of the default DefaultContext class or user-specified connection context classes.  

-methods=always 

This forces generation of .sqlj (as opposed to .java) source files for all JPublisher-generated classes, regardless of whether the underlying SQL object or package actually defines any methods. 

-compatible=customdatum 

For Oracle-specific object wrappers, this results in JPublisher implementing the older oracle.sql.CustomDatum and CustomDatumFactory interfaces (both deprecated but still supported in Oracle9i) instead of the newer oracle.sql.ORAData and ORADataFactory interfaces. 

-dir=. 

Setting this option to "." (a period or "dot") results in generation of output files into a hierarchy under the current directory, as was the default behavior in Oracle8i

Unless you have a compelling reason to use the backwards-compatibility settings, however, it is recommended that you accept the current default (or other) settings.

Oracle8i Compatibility Mode

The following setting results in what is called Oracle8i compatibility mode:

-compatible=8i

See "Backwards-Compatible Oracle Mapping for User-Defined Types (-compatible)" for more information about this option.

For use of this mode to be permissible, however, at least one of the following circumstances must hold:

JPublisher has the following functionality in Oracle8i compatibility mode:

Details of Datatype Mapping

As described previously, you can specify one of the following settings for datatype mappings when you use the type mapping options (-builtintypes, -lobtypes, -numbertypes, and -usertypes):

These mappings, described in "Overview of Datatype Mappings", affect the argument and result types JPublisher uses in the methods it generates.

The class that JPublisher generates for an object type will have getXXX() and setXXX() methods for the object attributes. The class that JPublisher generates for a VARRAY or nested table type will have getXXX() and setXXX() methods that access the elements of the array or nested table. When you use the option -methods=true, the class that JPublisher generates for an object type or PL/SQL package will have wrapper methods that invoke server methods of the object type or package. The mapping options control the argument and result types these methods will use.

The JDBC and Object JDBC mappings use familiar Java types that can be manipulated using standard Java operations. If your JDBC program is manipulating Java objects stored as object types, you might prefer the JDBC or Object JDBC mapping.

The Oracle mapping is the most efficient mapping. The oracle.sql types match the Oracle internal datatypes as closely as possible so that little or no data conversion is required. You do not lose any information and have greater flexibility in how you process and unpack the data. The Oracle mappings for standard SQL types are the most convenient representations if you are manipulating data within the database or moving data (for example, performing SELECT and INSERT operations from one existing table to another). When data format conversion is necessary, you can use methods in the oracle.sql.* classes to convert to Java native types.

When you decide which mapping to use, you should remember that data format conversion is only a part of the cost of transferring data between your program and the server.

Datatype Mapping Tables

Table 1-2 lists the mappings from SQL and PL/SQL datatypes to Java types using the Oracle and JDBC mappings. You can use all the supported datatypes listed in this table as argument or result types for PL/SQL methods. You can use a subset of the datatypes as object attribute types, as listed in "Allowed Object Attribute Types".

The SQL and PL/SQL Datatype column contains all possible datatypes.

The Oracle Mapping column lists the corresponding Java types JPublisher uses when all the type mapping options are set to oracle. These types are found in the oracle.sql package supplied by Oracle and are designed to minimize the overhead incurred when converting Oracle datatypes to Java types.

The JDBC Mapping column lists the corresponding Java types JPublisher uses when all the type mapping options are set to jdbc. For standard SQL datatypes, JPublisher uses Java types specified in the JDBC specification. For SQL datatypes that are Oracle extensions, JPublisher uses the oracle.sql.* types. Refer to the Oracle9i JDBC Developer's Guide and Reference for more information on the oracle.sql package.

A few datatypes are not currently supported by JPublisher, in some cases because they are not directly supported by Oracle SQLJ or JDBC, as noted in the table.

Table 1-2 PL/SQL Datatype to Oracle and Object JDBC Mapping Classes  
SQL and PL/SQL Datatype  Oracle Mapping  JDBC Mapping 

CHAR, CHARACTER, LONG, STRING, VARCHAR, VARCHAR2 

oracle.sql.CHAR 

java.lang.String 

NCHAR, NVARCHAR2  

not currently supported by JPublisher 

not currently supported by JPublisher 

RAW, LONG RAW 

oracle.sql.RAW 

byte[] 

BINARY_INTEGER, NATURAL, NATURALN, PLS_INTEGER, POSITIVE, POSITIVEN, SIGNTYPE, INT, INTEGER 

oracle.sql.NUMBER 

int 

DEC, DECIMAL, NUMBER, NUMERIC 

oracle.sql.NUMBER 

java.math.BigDecimal 

DOUBLE PRECISION, FLOAT 

oracle.sql.NUMBER 

double  

SMALLINT 

oracle.sql.NUMBER 

short 

REAL 

oracle.sql.NUMBER 

float 

DATE 

oracle.sql.DATE 

java.sql.Timestamp 

ROWID, UROWID 

oracle.sql.ROWID 

oracle.sql.ROWID 

BOOLEAN 

not directly supported by JDBC 

not directly supported by JDBC 

CLOB 

oracle.sql.CLOB 

java.sql.Clob 

BLOB 

oracle.sql.BLOB 

java.sql.Blob 

BFILE 

oracle.sql.BFILE 

oracle.sql.BFILE 

NCLOB 

not currently supported by JPublisher 

not currently supported by JPublisher 

object types 

generated class 

generated class 

SQLJ object types 

not directly supported by SQLJ 

not directly supported by SQLJ 

OPAQUE types 

not directly supported by SQLJ 

not directly supported by SQLJ 

RECORD types  

not directly supported by JDBC 

not directly supported by JDBC 

nested table, VARRAY  

generated class implemented using oracle.sql.ARRAY 

java.sql.Array 

reference to object type  

generated class implemented using oracle.sql.REF  

java.sql.Ref 

REF CURSOR 

java.sql.ResultSet  

java.sql.ResultSet 

index-by tables 

not directly supported by SQLJ 

not directly supported by SQLJ 

user-defined subtypes 

same as for base type 

same as for base type 

The Object JDBC and BigDecimal mappings, which affect numeric types only, are fully described in "Mappings For Numeric Types (-numbertypes)".

Allowed Object Attribute Types

You can use a subset of the PL/SQL datatypes listed in Table 1-2 as object attribute types. These datatypes are listed here and have the same Oracle mappings and JDBC mappings as described in the table:

Using Datatypes Not Supported by JDBC

JPublisher cannot generate wrapper methods for PL/SQL methods that use datatypes not directly supported by JDBC. If you must call a PL/SQL method that uses unsupported datatypes (such as BOOLEAN), you have two choices:

Concepts of JPublisher-Generated Classes

This section covers basic concepts about the code that JPublisher produces, including the following:

For more information, see the following sections later in this chapter:

Passing OUT Parameters

Stored procedures called through SQLJ do not have the same parameter-passing behavior as ordinary Java methods. This affects the code you write when you call a wrapper method 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.

In contrast, when you call a stored procedure through SQLJ, 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 parameter that has been modified appear in separate objects.

A wrapper method JPublisher generates contains SQLJ code to call a 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, and IN OUT. The IN OUT and OUT parameters of the stored procedure 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.

Passing Parameters Other Than the "this" Parameter

The simplest way to solve the problem described above is to pass an OUT or IN OUT parameter to the wrapper method in a single-element array. The array is a sort of container that holds the parameter.

In the following example, you have an initialized variable p of class Person, and x is an object belonging to a JPublisher-generated class that has a wrapper method f taking an IN OUT Person argument. You create the array and pass the parameter as follows:

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

Unfortunately, this technique for passing OUT or IN OUT parameters requires you to add a few extra lines of code to your program for each parameter. If your stored program has many OUT or IN OUT parameters, you might prefer to call it directly using SQLJ code, rather than a wrapper method.

Passing the "this" Parameter

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

The this object is an additional parameter that is 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, the wrapper method must return the new value of this. The code generated by JPublisher processes this in different ways, depending on the situation:

Translating Overloaded Methods

PL/SQL, as with Java, lets you create overloaded methods--two or more methods with the same name, but different signatures. If you use JPublisher to generate wrapper methods for PL/SQL methods, it is possible that two overloaded methods with different signatures in PL/SQL might have identical signatures in Java. If this occurs, JPublisher changes the names of the methods to avoid generating two or more methods with the identical signature. For example, consider a PL/SQL package or object type that includes these functions:

FUNCTION f(x INTEGER, y INTEGER) RETURN INTEGER 

and

FUNCTION f(xx FLOAT, yy FLOAT) RETURN INTEGER 

In PL/SQL, these functions have different argument types. However, once they are translated to Java with Oracle mapping, this difference disappears (both INTEGER and FLOAT map to oracle.sql.NUMBER).

Suppose that JPublisher generates a class for the package or object type with the command-line setting -methods=true and Oracle mapping. JPublisher responds by generating code similar to this:

  public oracle.sql.NUMBER f_1 ( 
    oracle.sql.NUMBER x, 
    oracle.sql.NUMBER y) 
  throws SQLException 
  { 
    /* body omitted */  
  } 
 
  public oracle.sql.NUMBER f_4 ( 
    oracle.sql.NUMBER xx, 
    oracle.sql.NUMBER yy) 
  throws SQLException 
  { 
    /* body omitted */ 
  } 
 

Note that in this example, JPublisher names the first function f_1 and the second function f_4. Each function name ends with _<nn>, where <nn> is a number assigned by JPublisher. The number has no significance of its own, but JPublisher uses it to guarantee that the names of functions with identical parameter types will be unique.

JPublisher Generation of SQLJ Classes

When -methods=true, JPublisher generates .sqlj files for PL/SQL packages and for object types (unless an object type does not define any methods, in which case a .java file is generated). The classes includes wrapper methods that invoke the server methods of the object types and packages. Run SQLJ to translate the .sqlj file.

This section describes how to use these generated classes in your SQLJ code.

Use of SQLJ Classes JPublisher Generates for PL/SQL Packages

To use a class that JPublisher generates for a PL/SQL package:

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, and 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. Oracle JDBC provides the constructor that takes a Connection instance for the convenience of the JDBC programmer who knows how to compile a SQLJ program, but is unfamiliar with SQLJ concepts such as DefaultContext.


Important:

Classes produced by JPublisher include a release() method. In creating and using an instance of a JPublisher-generated wrapper class, if you do not use the constructor with the DefaultContext argument, and you do not subsequently call the setConnectionContext() method with a connection context argument, and you invoke a wrapper method, then the wrapper object will implicitly construct a DefaultContext instance. In this case, use the release() method to release the connection context instance when it is no longer needed. See "Use of Connection Contexts and Instances in SQLJ Code Generated by JPublisher" for more information. 



Note:

In Oracle8i JPublisher and 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 (an instance of any class that implements the standard sqlj.runtime.ConnectionContext interface). 


The wrapper methods are all instance methods, because the connection context in the this object is used in #sql statements 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 you use. If the default context is the only one you use, call the no-argument constructor once. The Oracle9i SQLJ Developer's Guide and Reference discusses reasons for using explicit connection context instances.

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.

"Example: Using Classes Generated for Packages" shows how to use a class generated for a PL/SQL package.

Use of Classes JPublisher Generates for Object Types

To use an instance of a Java class that JPublisher generates for a SQL object type, you must first initialize the Java object.

To initialize your Java object, you can:

Once you have initialized your Java object, you can:

There is a Java attribute for each attribute of the corresponding SQL object type. The object has 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 executing in the server. The wrapper methods are all instance methods, regardless of whether the server methods are. The DefaultContext in the this object is used in #sql statements 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:

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

The RationalO example, described in "Example: Using Classes Generated for Object Types", shows how to use a class that was generated for an object type and has wrapper methods.

Use of Connection Contexts and Instances in SQLJ Code Generated by JPublisher

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:

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

Considerations in Using Connection Contexts and Connection Instances

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

See "Releasing Connection Context Resources" (below) and "SQLJ Connection Context Classes (-context)" for related information.

Releasing Connection Context Resources

In some situations, you must use the release() method of an instance of a JPublisher-generated wrapper class in order to free SQLJ runtime connection context resources. This is true in the following set of circumstances:

and:

and:

and:

and:

In these circumstances, a connection context instance would have been created implicitly on the object and must explicitly be freed through the release() method before the object goes out of scope.

(When there is an explicit connection context instance, such as through an explicit constructor or use of the setConnectionContext() method, using release() is not necessary.)

JPublisher Generation of Java Classes

When -methods=false, or when SQL object types do not define any methods, JPublisher does not generate wrapper methods for object types. Furthermore, when -methods=false, JPublisher does not generate code for PL/SQL packages at all, because they are not useful without wrapper methods. (Note that when -methods=false, JPublisher exclusively generates .java files.)

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

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

To initialize your object, you can:

Unlike the constructors generated in .sqlj source files, the constructors generated in .java source files do not take a connection argument. Instead, when your object is passed to or returned from a 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. On the contrary, this is not always possible. An object might 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 only construct a null reference. All non-null references come from the database.

Once you have initialized your object, you can accomplish 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 to the Oracle getORAData() methods in the classes ArrayDataResultSet, OracleCallableStatement, and OracleResultSet in the oracle.jdbc package. The Oracle JDBC driver uses the ORADataFactory object to create objects of your JPublisher-generated class.

In addition, classes representing VARRAYs and nested tables have a few 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 wrapper type to another.

The RationalP example, described in "Example: Using Classes Generated for Packages", includes a class that was generated for an object type that does not have wrapper methods.

User-Written Subclasses of JPublisher-Generated Classes

You might want to enhance the functionality of a custom Java class generated by JPublisher by adding methods and transient fields.

One way to accomplish this is to add methods directly to the JPublisher-generated class. 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, your changes (that is, the methods you have added) will be overwritten. Even if you direct JPublisher output to a separate file, you will still need to merge your changes into the file.

The preferred way to enhance the functionality of a generated class is to extend the class--that is, treat the JPublisher-generated class as a superclass, write a subclass to extend its functionality, then map the object type to the subclass.

This section discusses how to accomplish this.

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 JAddress provides.

Under this scenario, you can use JPublisher to generate a custom Java class JAddress, then write a subclass, MyAddress, which contains the added functionality. You then use JPublisher to map ADDRESS objects to the MyAddress class, not to the JAddress class. JPublisher will also produce a reference class for MyAddress, not JAddress.

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

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_class:map_class

For the above scenario, this would be:

-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 indicates the name of the class that JPublisher will generate (as JAddress.java), and MyAddress specifies the name of the class that you have written. JPublisher will map the object type ADDRESS to the MyAddress class, not to the JAddress class. Therefore, if you retrieve an object that has an ADDRESS attribute, this attribute will be created as an instance of MyAddress in Java. Or if you retrieve an ADDRESS object directly, you will retrieve it into an instance of MyAddress.

For an example of how you would use JPublisher to generate the JAddress class, see "Example: Generating a SQLData Class".

Writing the Class that Extends the Generated Class

The class that you create (for example, MyAddress.java) must have the following features:

"Example: Generating a SQLData Class" illustrates the preceding features.

Changes in User-Written Subclasses of Oracle9i JPublisher-Generated Classes

If you have been providing user-written subclasses for JPublisher-generated classes under Oracle8i JPublisher, you should be aware that there are a number of relevant changes in how Oracle9i JPublisher generates code. You would have to make changes in any applications written against the Oracle8i functionality if you want to use it under Oracle9i.


Note:

If you use the -compatible=8i option setting, you will not see the changes discussed here and your application will continue to build and work as before.

In general, however, it is generally advisable to make the transformation to Oracle9i JPublisher functionality, because this will help insulate your user code from implementation details of JPublisher-generated classes. 


Following are the changes:

The setFrom() and setValueFrom() Methods

Oracle9i JPublisher provides the following utility methods in generated .sqlj files:

JPublisher Support for Inheritance

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

This information is followed by 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 (
...
);

And consider the following JPublisher command line to create corresponding Java classes:

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

In this example, JPublisher generates a Person class and a Student class. The Student class extends the Person class, because STUDENT is a subtype of PERSON.

So initialization can complete properly, create instances of these classes--at least the leaf classes--before using these mapped types in your code. For example:

new Person();
new Student();

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.

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

You might think that the code for the create() method in the root class of a custom Java class hierarchy must mention all its subclasses. But if this were the case, you would have to modify the code for a base class when writing or generating a new subclass. At best, this process would be prone to errors, and would not even be possible if the programmer did not have access to the source code for the Java classes being extended.

Code generated by JPublisher solves this problem by creating a static initialization block in each subclass in 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 carries a small penalty--the static initialization blocks of the subclasses must be executed before the class hierarchy can be used to read objects from the database (or middle-tier database cache). 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 will invoke the constructor for its immediate superclass. 


To better understand how code generated by JPublisher supports inheritance, try an example similar to the one at the beginning of this section, and look at the generated code.

ORAData Reference Types and Inheritance

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

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 the example given in the previous section, repeated here for convenience:

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

CREATE TYPE STUDENT UNDER PERSON (
...
);

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

In addition to generating Person.sqlj (or .java) and Student.sqlj (or .java), JPublisher will generate PersonRef.java and StudentRef.java.

Because the Student class extends the Person class, you might 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 can do something that a StudentRef cannot do: modify a Person object in the database.

The most important methods of the PersonRef class would be the following:

The corresponding methods of the StudentRef class would be as follows:

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

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.

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. This section provides code to show you how to accomplish such a conversion in your program.

To convert from the reference type XxxxRef to the reference type YyyyRef, for example, use the following code:

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 comprises 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: Converting Between Reference Types" below provides sample code for such a conversion.


Note:

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


Example: 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

Java Class

Here is a Java class with an example of reference type conversion as discussed above, in "Converting Between Reference Types".

import java.sql.SQLException;
import java.sql.Connection;
import oracle.jdbc.OracleTypes;
import oracle.sqlj.runtime.Oracle;
import sqlj.runtime.ref.DefaultContext;
import sqlj.runtime.ResultSetIterator;

public class Inheritance
{
  public static void main(String[] args) throws SQLException
  {
    System.out.println("Connecting.");
    Oracle.connect("jdbc:oracle:oci:@","scott","tiger");

    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;

    System.out.println("Selecting a person.");
    #sql { select ref(p) INTO :p_ref FROM PERSON_TAB p WHERE p.NAME='Larry' };

    System.out.println("Selecting an instructor.");
    #sql { select ref(p) INTO :i_ref FROM PERSON_TAB p WHERE p.NAME='Smith' };

    System.out.println("Selecting a part time instructor.");
    #sql { select ref(p) INTO :ipt_ref FROM PERSON_TAB p WHERE p.NAME='Myers' };

    System.out.println("Selecting a student.");
    #sql { select ref(p) INTO :s_ref FROM PERSON_TAB p WHERE p.NAME='John' };

    System.out.println("Selecting a part time student.");
    #sql { select ref(p) INTO :spt_ref FROM PERSON_TAB p WHERE p.NAME='Dave' };

    System.out.println("Selecting a graduate student.");
    #sql { select ref(p) INTO :g_ref FROM PERSON_TAB p WHERE p.NAME='Lisa' };

    // Connection object for conversions
    Connection conn = DefaultContext.getDefaultContext().getConnection();

    // 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);

    // 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);

    // Assigning a graduate ref to an part time instructor ref
    // ==> this should actually bomb at runtime!
    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);
    Oracle.close();
  }
}

SQLData Object Types and Inheritance

As described earlier, if you use the JPublisher -usertypes=jdbc setting instead of -usertypes=oracle, the custom Java class that JPublisher generates will implement the standard SQLData interface instead of the Oracle ORAData interface. The SQLData 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 will follow the same hierarchy as the SQL types.

SQLData implementations do not, however, offer the implicit mapping intelligence that JPublisher automatically generates into 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 Oracle9i JDBC Developer's Guide and Reference for information.) In a SQLJ application, use a type map resource that is similar in nature to a properties file. (See the Oracle9i SQLJ Developer's Guide and Reference for information.)

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

Effect of Using SQL FINAL, NOT FINAL, INSTANTIABLE, NOT INSTANTIABLE

This section discusses the effect on JPublisher-generated wrapper classes of using the SQL modifiers FINAL, NOT FINAL, INSTANTIABLE, 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 the generated Java wrapper class through subclassing 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. Thus you must cast to some wrapper class that corresponds to an instantiable SQL subtype in order to call such a method.

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 only be created through subclasses that correspond to instantiable SQL types.

JPublisher Limitations

This section summarizes limitations in the current release of JPublisher.


Go to previous page Go to next page
Oracle
Copyright © 1996-2001, Oracle Corporation.

All Rights Reserved.
Go To Documentation Library
Home
Go To Product List
Book List
Go To Table Of Contents
Contents
Go To Index
Index

Master Index

Feedback