Oracle8i JPublisher User's Guide Release 2 (8.1.6) Part Number A81357-01 |
Library | Service | Contents | Index

## Understanding JPublisher

This section contains these subsections:

- Introduction

- JPublisher Requirements

- What JPublisher Does

- What JPublisher Produces

- Translating and Using PL/SQL Packages and Oracle Objects

- Representing User-defined Object, Collection, and REF Types in Your Program

- Sample JPublisher Command Line

- Sample JPublisher Translation

### Introduction

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

- database object types

- database reference (REF) types

- database collection types (`varrays` or nested tables)

- PL/SQL packages

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

JPublisher generates `get` and `set` 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 the database.

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. Therefore, JPublisher generates `.sqlj` source files for classes with wrapper methods, that is, classes representing object types or PL/SQL packages. JPublisher generates `.java` source files for classes representing REF or collection types. If you ask JPublisher to translate object types without generating wrapper methods, JPublisher will generate `.java` source files to represent the object types. You use SQLJ to compile the `.sqlj` files; you can use SQLJ or your Java compiler to compile the `.java` files.

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

- Extend the generated classes.

- Write your own Java classes by hand, without using JPublisher. This approach is quite flexible, but time-consuming and error-prone.

- Use generic classes to represent object, REF, and collection types. The `oracle.sql` package contains simple generic classes that represent object, REF, and collection types. If these classes meet your requirements, you do not need JPublisher.

##### Object Types and JPublisher

JPublisher allows your Java language applications to employ user-defined object types in an Oracle8 server. 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.CustomDatum` interface or the `java.sql.SQLData` interface. Either interface makes it possible to transfer object type instances between the database and your Java program. For more information on the `CustomDatum` interface, see the Oracle8i JDBC Developer's Guide and Reference . See The JDBC 2.0 API, by Sun Microsystems, for more information on the `SQLData` interface.

##### 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.

### JPublisher Requirements

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

- Oracle database version 8.1.6

- Oracle JDBC drivers version 8.1.6

- Java Developer's Kit (JDK) version 1.2

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

- If you never generate `SQLData` classes, and you never use the `java.sql.Blob` and `java.sql.Clob` classes, you can use JDK version 1.1.1 or higher, rather than JDK 1.2.

- If you never generate code for PL/SQL packages, you can use Oracle database version 8.1.5.

- If you never generate classes that implement the Oracle-specific `CustomDatum` interface, you should be able to use a non-Oracle JDBC driver or a non-Oracle SQLJ implementation. When running code generated by JPublisher, you should even be able to connect to a non-Oracle database; however, JPublisher itself must connect to an Oracle database. Oracle does not test or support configurations that use non-Oracle components.

- If you never use PL/SQL packages or classes that implement the `SQLData` interface (that is, you use JPublisher to generate only classes that implement the `CustomDatum` interface), you can use Oracle database version 8.1.5 with JDBC version 8.1.5 and JDK version 1.1.1 or higher.

- If you always tell JPublisher not to generate wrapper methods, you never generate any `.sqlj` files; therefore, you do not need to use SQLJ.

### 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 Net8 and required support files. If you do not have an Oracle client installation, JPublisher can use the Oracle Thin JDBC driver.

JPublisher generates a Java class for each database 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, you additionally must have the SQLJ runtime libraries.

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 `CustomDatum` classes (classes that implement the `oracle.sql.CustomDatum` interface) or `SQLData` classes (classes that implement the `java.sql.SQLData` interface).

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

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

- An object class that represents instances of the Oracle object type in your Java program.

- A related reference class for object references to your Oracle object type.

- Java classes for any object or collection attributes nested directly or indirectly within the top-level object. This is necessary so that attributes can be materialized in Java whenever an instance of the top-level class is materialized.

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

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

- a collection class to act as a type definition to correspond to your Oracle collection type

- if the elements of the collection are objects, a Java class for the element type, and Java classes for any object or collection attributes nested directly or indirectly within the element type

  This is necessary so that object elements can be materialized in Java whenever an instance of the collection is materialized.

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

- a Java class with wrapper methods that invoke the package's stored procedures

#### Type Mappings

JPublisher maps the Oracle datatypes of the object's attributes and the PL/SQL package's arguments and function results to Java, according to mappings you specify globally. You can request Oracle-style or JDBC-style mappings. For numeric types, two other mapping styles are available: Object JDBC style and BigDecimal style.

- The JDBC mapping is based on the default Java mappings for SQL datatypes, as given in section 8.1 of the JDBC specification. It maps most numeric database types to Java primitive types such as int and float, and it maps DECIMAL and NUMBER to java.math.BigDecimal. Non-numeric predefined types map to standard Java classes such as `java.lang.String` and `java.sql.Blob`, and object types map to `SQLData` classes.

- The Object JDBC mapping affects only numeric types and is based on the mappings from SQL types to Java object types, as given in section 14.2 of the JDBC specification. It maps most numeric database types to Java wrapper classes such as java.lang.Integer and java.lang.Float, and it maps DECIMAL and NUMBER to java.math.BigDecimal. This mapping is the default for numeric types.

- The BigDecimal mapping affects only numeric types. As the name suggests, it maps all numeric database types to java.math.BigDecimal.

- The Oracle mapping maps Oracle datatypes to their corresponding oracle.sql classes. All numeric attribute types map to oracle.sql.NUMBER; non-numeric types map to Oracle types such as oracle.sql.CHAR and oracle.sql.BLOB. User-defined types map to `CustomDatum` classes.

You can find a more detailed description of the Oracle, JDBC, and Object JDBC mappings in "Type Mappings for All Types (-mapping)" and "Understanding Datatype Mappings".

### Translating and Using PL/SQL Packages and Oracle Objects

Here are the basic steps for translating and using code for objects (including nested tables and `varray`s) and PL/SQL packages:

1. Create the desired object datatypes (Oracle objects) and PL/SQL packages in the database.

2. JPublisher generates source code for Java classes that represent PL/SQL packages, user-defined types, and `REF` types and places them in specified Java packages. JPublisher generates `.java` files for `REF`, `varray`, and nested table classes. If you ask JPublisher to generate wrapper methods, it will generate `.sqlj` files for object types and packages. If not, JPublisher will generate `.java` files without wrapper methods for object types and will not generate classes for packages (because they contain only wrapper methods).

3. Import these classes into your application code.

4. Use the methods in the generated classes to access and manipulate the Oracle objects and their attributes.

5. Compile all classes (the JPublisher-generated code and your code). The SQLJ compiler compiles the `.sqlj` files, and the Java or SQLJ 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

### Representing User-defined Object, Collection, and REF Types in Your Program

Here are the three ways in which you can represent user-defined object, collection, and `REF` types in your Java program:

- Use classes that implement the `SQLData` interface, as described in the JDBC 2.0 API.

  JPublisher generates classes for database object types that implement the `SQLData` interface. You can also write them by hand. If you write them by hand, your classes must then be registered using a type map.

  When you use the `SQLData` interface, all REF types are represented generically as instances of `java.sql.Ref`, and all collection types are represented generically as instances of `java.sql.Array`.

- Use `oracle.sql.*` classes.

  You can use the `oracle.sql.*` classes to represent user-defined types generically. The class `oracle.sql.STRUCT` represents all object types, the class `oracle.sql.ARRAY` represents all `VARRAY` and nested table types, and the class `oracle.sql.REF` represents all `REF` types. These classes are immutable in the same way that `java.lang.String` is.

- Use classes that implement the `CustomDatum` interface.

  JPublisher generates classes that implement the `CustomDatum` interface. You can also write them by hand.

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

Compared to `oracle.sql.*` classes, classes that implement `CustomDatum` 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 a `CustomDatum` that represents an `Address`.

JPublisher generated classes that implement `CustomDatum` or `SQLData` have additional advantages.

- The classes are customized, rather than generic. You access attributes of an object using `get` and `set` methods named after the particular attributes of the object.

- The classes are mutable. You can modify attributes of an object or elements of a collection. Exception: `CustomDatum` classes representing `REF` types are not mutable, because a `REF` does not have any subcomponents that could be sensibly modified.

### Sample JPublisher Command Line

On most operating systems, you invoke JPublisher on the command line. 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:

    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 convenience, this chapter refers to the input file (the file specified by the `-input` option) as the `INPUT` file.

This command causes JPublisher to connect to the database with username `scott` and password `tiger` and translate database types 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` directs JPublisher to generate Oracle-specific `CustomDatum` 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.

### Sample JPublisher Translation

This section illustrates a sample JPublisher translation of a simple 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 chapter.

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 command line:

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

Because -`dir=demo` was specified on the JPublisher command line, the package `corp` with the translated class `employee` is written to the file:

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

The `Employee.sqlj` class file would contain this code:

Note: The details of the code JPublisher generates are subject to change in future releases. In particular, non-public methods, non-public fields, and all method bodies are subject to change.

    package corp;

    import java.sql.SQLException;
    import oracle.jdbc.driver.OracleConnection;
    import oracle.jdbc.driver.OracleTypes;
    import oracle.sql.CustomDatum;
    import oracle.sql.CustomDatumFactory;
    import oracle.sql.Datum;
    import oracle.sql.STRUCT;
    import oracle.jpub.runtime.MutableStruct;
    import sqlj.runtime.ref.DefaultContext;
    import sqlj.runtime.ConnectionContext;
    import java.sql.Connection;

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

      #sql static context _Ctx;
      _Ctx _ctx;

      MutableStruct _struct;

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

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

      static final Employee _EmployeeFactory = new Employee();
      public static CustomDatumFactory getFactory()
      {
        return _EmployeeFactory;
      }

      /* constructors */
      public Employee()
      {
        _struct = new MutableStruct(new Object[5], _sqlType, _factory);
        try
        {
          _ctx = new _Ctx(DefaultContext.getDefaultContext());
        }
        catch (Exception e)
        {
          _ctx = null;
        }
      }

      public Employee(ConnectionContext c) throws SQLException
      {
        _struct = new MutableStruct(new Object[5], _sqlType, _factory);
        _ctx = new _Ctx(c == null ? DefaultContext.getDefaultContext()
                                  : c);
      }
      public Employee(Connection c) throws SQLException
      {
        _struct = new MutableStruct(new Object[5], _sqlType, _factory);
        _ctx = new _Ctx(c);
      }

      /* CustomDatum interface */
      public Datum toDatum(OracleConnection c) throws SQLException
      {
        _ctx = new _Ctx(c);
        return _struct.toDatum(c, _SQL_NAME);
      }

      /* CustomDatumFactory interface */
      public CustomDatum create(Datum d, int sqlType) throws SQLException
      {
        if (d == null) return null;
        Employee o = new Employee();
        o._struct = new MutableStruct((STRUCT) d, _sqlType, _factory);
        o._ctx = new _Ctx(((STRUCT) d).getConnection());
        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 int getEmpno() throws SQLException
      { return ((Integer) _struct.getAttribute(1)).intValue(); }

      public void setEmpno(int empno) throws SQLException
      { _struct.setAttribute(1, new Integer(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)).floatValue(); }

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

    }

JPublisher also generates an `EmployeeRef.java` class. The contents of this file are displayed below.

    package corp;

    import java.sql.SQLException;
    import oracle.jdbc.driver.OracleConnection;
    import oracle.jdbc.driver.OracleTypes;
    import oracle.sql.CustomDatum;
    import oracle.sql.CustomDatumFactory;
    import oracle.sql.Datum;
    import oracle.sql.REF;
    import oracle.sql.STRUCT;

    public class EmployeeRef implements CustomDatum, CustomDatumFactory
    {
      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 CustomDatumFactory getFactory()
      {
        return _EmployeeRefFactory;
      }

      /* constructor */
      public EmployeeRef()
      {
      }

      /* CustomDatum interface */
      public Datum toDatum(OracleConnection c) throws SQLException
      {
        return _ref;
      }

      /* CustomDatumFactory interface */
      public CustomDatum 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.getFactory().create(
           _ref.getSTRUCT(), OracleTypes.REF);
      }

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

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

| Copyright © 1996-2000, Oracle Corporation. All Rights Reserved. |
Library | Service | Contents | Index