Oracle9i JPublisher User's Guide Release 2 (9.2) Part Number A96658-01 |
|
This chapter starts with a brief introduction and examples for the JPublisher utility, followed by a more complete overview. The following topics are covered:
If you are new to JPublisher, start with "Invitation to JPublisher". If you have used JPublisher before, you may want to skip ahead to "New JPublisher Features in Oracle9i Release 2".
This section gives you an introduction to basic features and new features in Oracle9i release 2 (9.2).
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 get
XXX
()
and set
XXX
()
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:
oracle.sql
package contains generic, weakly typed classes that represent object, object reference, and collection types. If these classes meet your requirements, you do not need JPublisher. Typically, you would use this approach if you need to be able to generically process any SQL object, collection, reference, or OPAQUE type.In addition, JPublisher simplifies access to PL/SQL only types from Java. You can employ predefined or user-defined mappings between PL/SQL and SQL types, as well as make use of PL/SQL conversion functions between such types. With such type correspondences in place, JPublisher can automatically generate all of the required Java and PL/SQL code.
JPublisher is distributed with the Oracle SQLJ translator. If you have installed SQLJ through the Oracle Installer, you should already be set up. If you have manually downloaded a version of Oracle SQLJ, however, you have to go through a few manual steps to ensure you can use SQLJ and JPublisher. You can refer to instructions in the Oracle9i SQLJ Developer's Guide and Reference.
You must ensure the following:
javac
compiler from the command line.[Oracle_Home]/jdbc/classes
XX
.jar
.[Oracle_Home]/sqlj/runtime
XX
.jar
and [Oracle_Home]/sqlj/translator.jar
.jpub
or jpub.exe
, sqlj
or sqlj.exe
--are in your file path, typically [Oracle_Home]/bin
or (for manual downloads) [Oracle_Home]/sqlj/bin
.
With proper setup, if you type jpub
to the command line you will see information about common JPublisher option and input settings.
Additionally, if you use JPublisher from release 9.2.0 or later against a 9.2.0 or later Oracle database, the PL/SQL package SYS.SQLJUTL
should be installed. If your database is Java-enabled, this is already the case. If not, have your database administrator install the SQL script [Oracle_Home]/sqlj/lib/sqljutl.sql
into the SYS
schema.
Note: This rest of this section provides introductory discussion and examples. For more examples, go to |
It is straightforward to use JPublisher for publishing SQL objects and packages as Java classes. This section provides examples of this for the OE
(Order Entry) schema that is part of the Oracle9i sample schema (see Oracle9i Sample Schemas for detailed information). If you do not have the sample schema installed, but have your own object types or packages that you would like to publish, just replace the user name, password, and object or package names with your own.
Assuming that the password for the OE
schema is OE
, this is how you can publish the SQL object type CATEGORY_TYP
:
jpub -user=OE/OE -sql=CATEGORY_TYP:CategoryTyp
Use the JPublisher -user
option to specify the user name (schema name) and password. The -sql
option specifies the types and packages to be published. CATEGORY_TYP
is the name of the SQL type and, separated by a colon (":"), CategoryTyp
is the name of the corresponding Java class to be generated. JPublisher echoes to the standard output the names of the SQL types and packages that it is publishing:
OE.CATEGORY_TYP
When you list the files in your current directory, you will notice that in addition to the file CategoryTyp.java
, which you would have expected, JPublisher has also generated a file CategoryTypeRef.java
. This represents a strongly typed wrapper for SQL object references to OE.CATEGORY_TYP
. Both files are ready to be compiled with the Java compiler javac
.
Here is another example, for the type CUSTOMER_TYP
, using the shorthand -u
(followed by a space) for "-user=
" and -s
for "-sql=
":
jpub -u OE/OE -s CUSTOMER_TYP:CustomerTyp
JPublisher output:
OE.CUSTOMER_TYP OE.CUST_ADDRESS_TYP OE.PHONE_LIST_TYP OE.ORDER_LIST_TYP OE.ORDER_TYP OE.ORDER_ITEM_LIST_TYP OE.ORDER_ITEM_TYP OE.PRODUCT_INFORMATION_TYP OE.INVENTORY_LIST_TYP OE.INVENTORY_TYP OE.WAREHOUSE_TYP
JPublisher reports a list of SQL object types, because whenever it encounters an object type for the first time (whether it is an attribute, an object reference, or a collection that has element types which themselves are objects or collections), it will automatically generate a wrapper class for that type as well. Two wrapper files are generated for each object type in this example: 1) a Java class, such as CustomerTyp
, to represent instances of the object type; and 2) a reference class, such as CustomerTypeRef
, to represent references to the object type. You may also have noticed the naming scheme that JPublisher uses by default: the SQL type OE.PRODUCT_INFORMATION_TYP
turns into a Java class ProductInformationTyp
, for example.
Even though JPublisher automatically generates wrappers for embedded types, it will not do so for subtypes of given object types. In this case, you have to explicitly enumerate all of the subtypes that you want to have published. The CATEGORY_TYP
type has three subtypes: LEAF_CATEGORY_TYP
, COMPOSITE_CATEGORY_TYP
, and CATALOG_TYP
. The following is a single wraparound JPublisher command line to publish these object types.
jpub -u OE/OE -s COMPOSITE_CATEGORY_TYP:CompositeCategoryTyp -s LEAF_CATEGORY_TYP:LeafCategoryTyp,CATALOG_TYP:CatalogTyp
JPublisher output:
OE.COMPOSITE_CATEGORY_TYP OE.SUBCATEGORY_REF_LIST_TYP OE.LEAF_CATEGORY_TYP OE.CATALOG_TYP OE.CATEGORY_TYP OE.PRODUCT_REF_LIST_TYP
Note the following:
-sql
(-s
) option, separated by commas , or you can supply several -sql
options on the command line, or you can do both.CatalogTyp
, a .java
file was output. This time, however, JPublisher created .sqlj
files for CATALOG_TYP
and its three subtypes.
This is because SQLJ simplifies the coding of SQL invocations from Java. Whenever a SQL object type contains methods, JPublisher by default will generate a .sqlj
file that includes wrappers for these methods as well. Both .sqlj
and .java
files can be immediately translated and compiled with the Oracle SQLJ translator, as follows:
sqlj *.sqlj *.java
If you are generating Java wrappers for a SQL type hierarchy, and one or more of the types contain methods (as is the case here), then JPublisher will automatically generate .sqlj
files for all types in the hierarchy. Note that you can always suppress the generation of method wrappers and thus of .sqlj
files with the JPublisher option -methods=false
.
In case the code generated by JPublisher does not give you the functionality or behavior you want, you can subclass generated wrapper classes in order to override or complement their functionality. Consider the following example:
jpub -u OE/OE -s WAREHOUSE_TYP:JPubWarehouse:MyWarehouse
JPublisher output:
OE.WAREHOUSE_TYP
With this command, JPublisher generates JPubWarehouse.java
as well as MyWarehouse.java
. The file JPubWarehouse.java
is regenerated every time you rerun this command. The file MyWarehouse.java
is created in order to be customized by you, and will not be overwritten by future runs of this JPublisher invocation. You can add new methods in MyWarehouse.java
, override the method implementations from JPubWarehouse.java
, or both. The class used to materialize WAREHOUSE_TYP
instances in Java is the specialized class MyWarehouse
. If you want user-specific subclasses for all types in an object type hierarchy, you will have to specify "triplets" of the form SQL_TYPE
:
JPubClass
:
UserClass
as above for all members of the hierarchy.
Now that we have generated and compiled some Java wrapper classes--how do you actually use them in Java programs?
Once you have generated and compiled Java wrapper classes with JPublisher, using them is fairly straightforward, especially if you are programming in SQLJ--just use the object wrappers directly. The following example calls a PL/SQL stored procedure that takes a WAREHOUSE_TYPE
instance as an IN OUT
parameter:
java.math.BigDecimal location = ...; java.math.BigDecimal warehouseId = ...; MyWarehouse w = new MyWarehouse(warehouseId,"Industrial Park",location); ... #sql { call register_warehouse(:INOUT w) };
In JDBC, you typically register the relationship between the SQL type name and the corresponding Java class in the type map for your connection instance. This is required once per connection, as in the following example:
java.util.Map typeMap = conn.getTypeMap(); typeMap.put("OE.WAREHOUSE_TYP", MyWarehouse.class); conn.setTypeMap(typeMap);
The following JDBC code corresponds to the #sql
statement shown earlier.
CallableStatement cs = conn.prepareCall("{call register_warehouse(?)}"); ((OracleCallableStatement)cs).registerOutParameter (1,oracle.jdbc.OracleTypes.STRUCT,"OE.WAREHOUSE_TYP"); cs.setObject(w); cs.executeUpdate(); w = cs.getObject(1);
As shown in the preceding section, it is straightforward to use SQLJ code to call PL/SQL stored procedures or functions. However, you might prefer to encapsulate entire PL/SQL packages as Java classes, and JPublisher also offers functionality for this.
The concept of representing PL/SQL functions and procedures as Java methods presents a problem--arguments to such functions or procedures might use the PL/SQL mode OUT
or IN OUT
, but there are no equivalent modes for passing arguments in Java. A method that takes an int
argument, for example, is not able to modify this argument in such a way that its callers can receive a new value for it. As a workaround, JPublisher generates single-element arrays for OUT
and IN OUT
arguments. For an array int[] abc
, for example, the input value is provided in abc[0]
, and the modified output value is also returned in abc[0]
. A similar pattern is also used by JPublisher when generating code for SQL object type methods.
The following command line publishes the SYS.DBMS_LOB
package into Java:
jpub -u SCOTT/TIGER -s SYS.DBMS_LOB:DbmsLob
JPublisher output:
SYS.DBMS_LOB
Since DBMS_LOB
is publicly visible, we can access it from a different schema, such as SCOTT
. Note that this JPublisher invocation creates a SQLJ source file DbmsLob.sqlj
that contains the calls to the PL/SQL package. The generated Java methods are actually all instance methods. The idea is that you create an instance of the package using a JDBC connection or a SQLJ connection context and then call the methods on that instance.
When you examine the generated code, notice that JPublisher has generated java.lang.Integer
as arguments to various methods. Using Java object types such as Integer
instead of Java primitive types such as int
permits you to represent SQL NULL
values directly as Java null
s, and JPublisher generates these by default. However, for the DBMS_LOB
package we actually prefer int
over the object type Integer
. The following modified JPublisher invocation accomplishes this through the -numbertypes
option.
jpub -numbertypes=jdbc -u SCOTT/TIGER -s SYS.DBMS_LOB:DbmsLob
JPublisher output:
SYS.DBMS_LOB
JPublisher also allows you to generate wrapper code for the functions and procedures at the SQL top level. Use the special package name TOPLEVEL
, as in the following example:
jpub -u SCOTT/TIGER -s TOPLEVEL:SQLTopLevel
JPublisher output:
SCOTT.<top-level_scope>
You will see a warning if there are no stored functions or procedures in the SQL top-level scope.
If your stored procedures or functions use types that are specific to PL/SQL and not supported from Java, you will receive warning messages and no corresponding Java methods are generated. However, you may be able to map PL/SQL types to corresponding SQL types and their Java counterparts, which will permit JPublisher to generate appropriate Java code, and possibly PL/SQL code, to gain access to these types from Java. (See "Using Datatypes Unsupported by JDBC".)
With Oracle9i release 2 (9.2), JPublisher supports virtually all types that can be used with the Oracle JDBC drivers. Additionally, JPublisher facilitates the use of PL/SQL types in stored procedure and object method signatures through PL/SQL conversion support. The following Oracle JDBC types are now directly supported:
Specifically, the OPAQUE type SYS.XMLTYPE
is supported through the Java type oracle.xdb.XMLType
. SQL OPAQUE types can be supported through a predefined type correspondence or can trigger JPublisher code generation. (See "Type Mapping Support for OPAQUE Types".)
Native PL/SQL types can now be more easily accessed by JPublisher code through the automatic generation of PL/SQL wrapper functions and procedures in conjunction with the following mechanisms:
BOOLEAN
and Java boolean
, or PL/SQL INTERVAL
and Java String
See "Type Mapping Support Through PL/SQL Conversion Functions".
See "Type Mapping Support for Scalar Indexed-by Tables Using JDBC OCI".
JPublisher now provides improved functionality as well as flexibility in the code it generates, as follows:
See "Serializability of Generated Object Wrappers (-serializable)".
toString()
methods that report the object value.
See "Generation of toString() Method on Object Wrappers (-tostring)".
JPublisher now reduces the programming effort even further, as follows:
Make
environments.This section provides a basic understanding of what JPublisher is for and what it accomplishes, covering the following topics:
JPublisher provides mappings from the following SQL entities to Java classes:
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 and your Java program. For more information about the ORAData
and SQLData
interfaces, see the Oracle9i JDBC Developer's Guide and Reference.
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 can generate a class containing wrapper methods for all top-level procedures and functions, or for a subset of the top-level subprograms that you request.
Java programs only permit you to use SQL types when calling PL/SQL stored procedures or functions. Types that are supported by PL/SQL only, such as BOOLEAN
, PL/SQL RECORD types, and PL/SQL indexed-by tables cannot be accessed by JDBC programs. One exception to this are scalar PL/SQL indexed-by tables which are currently supported in the client-side JDBC OCI driver only.
JPublisher simplifies the invocation of stored procedures and functions that contain such types: it will automatically create a package with PL/SQL wrapper procedures and functions, as necessary, to convert between signatures containing PL/SQL types and corresponding ones that can be used from Java programs and that reference SQL types only. A mapping has been predefined for the BOOLEAN
type. However, in general users will have to provide correspondences and conversions between SQL and PL/SQL in order for JPublisher to incorporate a particular PL/SQL type into its code generation.
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 Oracle9i 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. Note that this results in a database round trip. If the method call only performs a simple state change on the object, it will be much more performant to write and use equivalent Java that affects the state change locally.
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. In addition, JPublisher may also generate a PL/SQL wrapper package, if required, for converting signatures containing PL/SQL types into corresponding ones containing SQL types only.
The next section furnishes a general description of the source files that JPublisher creates for object types and PL/SQL packages.
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, collection, and OPAQUE types in a strongly typed way. That is, for each specific object, object reference, collection, or OPAQUE 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, collection, and OPAQUE 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:
This is necessary so that attributes can be materialized in Java whenever an instance of the top-level class is materialized. If an attribute type, such as a SQL OPAQUE type or a PL/SQL type, has been pre-mapped, then JPublisher will use the target Java type from the map.
Note: For Advantages of using strongly typed instead of weakly typed references are described in "Strongly Typed Object References for ORAData Implementations". |
If you request SQLData
classes instead, JPublisher does not generate the object reference class and does not generate classes for nested collection attributes or for OPAQUE attributes.
When you run JPublisher for a user-defined collection type, you must request ORAData
classes. JPublisher automatically creates the following:
This is necessary so object elements can be materialized in Java whenever an instance of the collection is materialized.
When you run JPublisher for an OPAQUE type, you must request ORAData
classes. JPublisher automatically creates:
protected
APIs to access the representation of the OPAQUE type in a subclass
Typically, however, Java wrapper classes for SQL OPAQUE types will be furnished by the provider of the OPAQUE type, such as, for example, oracle.xdb.XMLType
for the SQL OPAQUE type SYS.XMLTYPE
. In this case, ensure that the correspondence between the SQL and the Java type is predefined to JPublisher.
When you run JPublisher for a PL/SQL package, it automatically creates the following:
This may also be generated if you translate methods of an object type, and PL/SQL wrappers are needed for converting PL/SQL to SQL arguments and vice versa.
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 (available as .jar
or .zip
files):
translator
)runtime12
, runtime12ee
, or runtime11
)classes12, ojdbc14,
or classes111
)"12
" refers to versions for JDK 1.2.x or later; "14
" refers to versions for JDK 1.4.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 an Oracle9i release 2 or later database, then the package SQLJUTL
should also be installed and publicly accessible in the SYS
schema. If this is not the case, you will see the following warning message when you invoke JPublisher:
Warning: Cannot determine what kind of type is <
schema
>.<
type.
> You likely need to install SYS.SQLJUTL. The database returns: ORA-06550: line 1, column 7:
PLS-00201: identifier 'SYS.SQLJUTL' must be declared
In this situation, ask your database administrator to install the SQL file [Oracle Home]/sqlj/lib/sqljutl.sql
into the SYS
schema and make it publicly accessible. This will avoid the above warning message in the future.
When you use Oracle9i JPublisher, it is typical to use the equivalent version of SQLJ, because these two products are always installed together. To use all features of JPublisher, you also need the following.
If you are using only some features of JPublisher, your requirements might be less stringent:
SQLData
classes, and you never use the java.sql.Blob
and java.sql.Clob
classes, you can use JDK version 1.1.x instead of JDK 1.2.x.ORAData
interface (or the deprecated 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.-methods=false
), or if your object types define no methods, then JPublisher will not generate wrapper methods or produce any .sqlj
files. In this case, you would not need the SQLJ translator. See "Generation of Package Classes and Wrapper Methods (-methods)" for information about the -methods
option.CustomDatum
interface, you can use Oracle database version 8.1.5 with JDBC version 8.1.5 and JDK version 1.1.x or higher. (But it is advisable to upgrade to the ORAData
interface, which requires an Oracle9i or higher JDBC implementation.)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 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 options to JPublisher. Specify the names of properties files on the command line, using the -props
option. JPublisher processes the properties files as if their contents were inserted, in sequence, on the command line at that point. For additional flexibility, properties files can also be SQL script files where the JPublisher directives are embedded in SQL comments. For more information about this file and its format, see "Properties File Structure and Syntax".
JPublisher generates a Java class for each object type that it translates. For each object type, whether an ORAData
or a SQLData
implementation, JPublisher generates a <
type
>.sqlj
file for the class code (or a <
type
>.java
file if wrapper methods were suppressed or do not exist, or depending on the JPublisher -methods
option setting) 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. JPublisher can also generate wrapper classes for OPAQUE types. However, OPAQUE types are more typically already pre-mapped to corresponding Java classes that implement the ORAData
interface.
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.
JPublisher offers different categories of datatype mappings from SQL to Java. JPublisher options to specify these mappings are described below, under "Detailed Descriptions of 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".
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.
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, as the name implies, maps all numeric datatypes to java.math.BigDecimal
. It supports null values and very large values.
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.
Note that a number of additional option settings influence the nature of the generated code. For example, the option -compatible
controls generations of the backward compatible CustomDatum
type, while -access
specifies the visibility of the generated methods, constructors, and attributes. The option -serializable
controls whether a generated object wrapper class implements java.io.Serializable
or not.
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:
public
and private
procedures, variables, constants, and cursorsFor more information on PL/SQL and creating PL/SQL packages, see the PL/SQL User's Guide and Reference.
This section discusses the basic steps in using JPublisher, describes the command-line syntax, and concludes with a more detailed description of a sample translation. The following topics are covered:
This section lists the basic steps, illustrated in Figure 1-1 below, 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 table types.
.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..sqlj
and .java
files. Or, if you have only .java
files, you can simply invoke the Java compiler.Text description of the illustration transobj.jpg
Here are the three ways to represent user-defined object, collection, object reference, and OPAQUE types in your Java program:
ORAData
interface.
JPublisher generates classes that implement the oracle.sql.ORAData
interface. (You can also write them by hand, but this is not generally recommended.)
SQLData
interface, as described in the JDBC 2.0 API.
JPublisher generates classes for SQL object types that implement the java.sql.SQLData
interface. (You can also write them by hand, but this is not generally recommended. Be aware that if you write them by hand, or if you generate classes for an inheritance hierarchy of object types, your classes must be registered using a type map.)
When you use the SQLData
interface, all object reference types are represented generically as java.sql.Ref
instances, and all collection types are represented generically as java.sql.Array
instances. There is no mechanism for representing OPAQUE types.
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, the class oracle.sql.REF
represents all REF types, and the class oracle.sql.OPAQUE
represents all OPAQUE types. These classes are immutable in the same way that java.lang.String
is.
You would need to choose this option if you need to write code that processes objects, collections, references, or OPAQUE types in a generic way.
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:
get
XXX
()
and set
XXX
()
methods named after the particular attributes of the object. Note that you have to explicitly update the object in the database if there are any changes to its data.ORAData
classes representing object reference types are not mutable, because an object reference does not have any subcomponents that could be sensibly modified. You can, however, use the setValue()
method of a reference object to change the database value that the reference points to.toString()
method to print out the object together with its attribute values.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.
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 oracle.sql.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. In addition, JPublisher also generates a static cast()
method on the PersonRef
class, permitting you to convert other typed references to a PersonRef
instance.
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.
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 (single wraparound command line):
jpub -user=scott/tiger -input=demoin -numbertypes=oracle -usertypes=oracle -dir=demo -package=corp
Enter the command on one command 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:
|
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 wraparound 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; private static int[] _sqlType = { 12,4,2,91,7 }; private static ORADataFactory[] _factory = new ORADataFactory[5]; protected static final Employee _EmployeeFactory = new Employee(false); 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); } public Employee(String name, Integer empno, java.math.BigDecimal deptno, java.sql.Timestamp hiredate, Float salary) throws SQLException { this(true); setName(name); setEmpno(empno); setDeptno(deptno); setHiredate(hiredate); setSalary(salary); } /* 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); } }
private
or public
methods may be generated with other settings. For example, the setting -serializable=true
results in the object wrapper implementing the interface java.io.Serializable
and in the generation of private
writeObject
and readObject
methods. The setting -tostring=true
results in the additional generation of a public
toString()
method.protected
_struct
field in JPublisher-generated code for SQL object types. This is an instance of the internal class oracle.jpub.runtime.MutableStruct
; this instance contains the data in original SQL format. In general, you should never reference this field directly. Instead, use the setting -methods=always
or -methods=named
as necessary to ensure that JPublisher produces .sqlj
files, then use the methods setFrom()
and setValueFrom()
when subclassing. See "The setFrom(), setValueFrom(), and setContextFrom() Methods".protected
_ctx
field that is a SQLJ connection context instance. See "Oracle8i Compatibility Mode" for more information.CustomDatum
and CustomDatumFactory
interfaces, instead of ORAData
and ORADataFactory
. In fact, it is still possible to do this through the JPublisher -compatible
option, and this is required if you are using an Oracle8i JDBC driver.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; private static final EmployeeRef _EmployeeRefFactory = new EmployeeRef(); public static ORADataFactory getORADataFactory() { return _EmployeeRefFactory; } /* constructor */ public EmployeeRef() { } /* ORAData interface */ public Datum toDatum(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 static EmployeeRef cast(ORAData o) throws SQLException { if (o == null) return null; try { return (EmployeeRef) getORADataFactory().create(o.toDatum(null), OracleTypes.REF); } catch (Exception exn) { throw new SQLException("Unable to convert "+o.getClass().getName()+" to EmployeeRef: "+exn.toString()); } } 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())); } }
Note that JPublisher in Oracle9i release 2 and higher also generates a public static cast()
method to cast from other strongly typed references into a strongly typed reference instance.
You can find more examples of object mappings in "Example: JPublisher Object Attribute Mapping".
|
Copyright © 1999, 2002 Oracle Corporation. All Rights Reserved. |
|