| Oracle8i JDBC Developer's Guide and Reference Release 8.1.5 A64685-01 |
|
This section contains the following subsections:
This section contains examples of the code you must provide to create custom Java classes for Oracle objects. You create the custom classes by implementing either the SQLData or CustomDatum interface. These interfaces provide a way to create and populate the custom Java class for the Oracle object and its attributes.
Although both SQLData and CustomDatum both populate a Java object from a SQL object, the CustomDatum interface is far more powerful. In addition to letting you populate Java objects, CustomDatum lets you materialize objects from SQL types that are not necessarily objects. Thus, you can create a CustomDatum object from any datatype found in an Oracle database. This is particularly useful in the case of RAW data that can be a serialized object.
The SQLData interface is a JDBC standard. For more information on this interface, see "Understanding the SQLData Interface".
The CustomDatum interface is provided by Oracle. You can write your own code to create custom Java classes that implement this interface, but you will find it easier to let the Oracle utility JPublisher create the custom classes for you. The custom classes created by JPublisher implement the CustomDatum interface.
For more information on the CustomDatum interface, see "Understanding the CustomDatum Interface". See the Oracle8i JPublisher User's Guide for more information on the JPublisher utility.
This section contains a code sample that illustrates how you can create a custom Java type to correspond to a given SQL type. It then demonstrates how you can use the custom Java class in the context of a sample program. The sample also contains the code to map the SQL type to the custom Java type.
Following is the SQL definition of an EMPLOYEE object. The object has two attributes: a string EmpName (employee name) attribute and an integer EmpNo (employee number) attribute.
-- SQL definition CREATE TYPE EMPLOYEE AS OBJECT ( EmpName VARCHAR2(50), EmpNo INTEGER, );
The following program implements the custom Java class EmployeeObj to correspond to the SQL type EMPLOYEE. Notice that the implementation of EmployeeObj contains a string EmpName (employee name) attribute and an integer EmpNo (employee number) attribute. Also notice that the Java definition of the EmployeeObj custom Java class implements the SQLData interface and includes the implementations of a get method and the required readSQL() and writeSQL() methods.
import java.sql.*; import oracle.jdbc2.*; public class EmployeeObj implements SQLData { private String sql_type; public String empName; public int empNo; public EmployeeObj() { } // line 14 public EmployeeObj (String sql_type, String empName, int empNo) { this.sql_type = sql_type; this.empName = empName; this.empNo = empNo; } // line 20 ////// implements SQLData ////// // define a get method to return the SQL type of the object line 24 public String getSQLTypeName() throws SQLException { return sql_type; } // line 28 // define the required readSQL() method line 30 public void readSQL(SQLInput stream, String typeName) throws SQLException { sql_type = typeName; empName = stream.readString(); empNo = stream.readInt(); } // define the required writeSQL() method line 39 public void writeSQL(SQLOutput stream) throws SQLException { stream.writeString(empName); stream.writeInt(empNo); } }
Import the needed java.* and oracle.* packages. Define the custom Java class EmployeeObj to implement the SQLData interface. EmployeeObj is the class to which you will later map your EMPLOYEE SQL object type. The EmployeeObj object has three attributes: a SQL type name, an employee name, and an employee number. The SQL type name is a Java string that represents the fully qualified SQL type name (schema.sql_type_name) of the Oracle object that the custom Java class represents.
Define a getSqlType() method to return the SQL type of the custom Java object.
Define a readSQL() method as required by the definition of the SQLData interface. The readSQL() method takes a stream SQLInput object and the SQL type name of the object data that it is reading.
Define a writeSQL() method as required by the definition of the SQLData interface. The writeSQL() method takes a stream SQLOutput object and the SQL type name of the object data that it is reading.
After you create your EmployeeObj Java class, you can use it in a program. The following program creates a table that stores employee name and number data. The program uses the EmployeeObj object to create a new employee object and insert it in the table. It then applies a SELECT statement to get the contents of the table and prints its contents.
Except for some changes to the comments, the following sample is similar to the SQLDataExample.java program in the Demo/samples/oci8/object-samples directory.
import java.sql.*; // line 1 import oracle.jdbc.driver.*; import oracle.sql.*; import java.math.BigDecimal; import java.util.Dictionary; public class SQLDataExample { public static void main(String args []) throws Exception { // Connect to the database DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver ()); OracleConnection conn = (OracleConnection) DriverManager.getConnection("jdbc:oracle:oci8:@", "scott", "tiger"); // line 16 // in the type map, add the mapping of EMPLOYEE SQL // line 18 // type to the EmployeeObj custom Java type Dictionary map = conn.getTypeMap(); map.put("EMPLOYEE", Class.forName("EmployeeObj")); // line 21 // Create a Statement line 23 Statement stmt = conn.createStatement (); try { stmt.execute ("drop table EMPLOYEE_TABLE"); stmt.execute ("drop type EMPLOYEE"); } catch (SQLException e) { // An error is raised if the table/type does not exist. Just ignore it. } // Create and populate tables // line 35 stmt.execute ("CREATE TYPE EMPLOYEE AS OBJECT(EmpName VARCHAR2(50), EmpNo INTEGER)"); stmt.execute ("CREATE TABLE EMPLOYEE_TABLE (ATTR1 EMPLOYEE)"); stmt.execute ("INSERT INTO EMPLOYEE_TABLE VALUES (EMPLOYEE('Susan Smith', 123))"); // line 40 // Create a SQLData object EmployeeObj in the SCOTT schema EmployeeObj e = new EmployeeObj("SCOTT.EMPLOYEE", "George Jones", 456); // Insert the SQLData object into the database // line 45 PreparedStatement pstmt = conn.prepareStatement ("INSERT INTO employee_table VALUES (?)"); pstmt.setObject(1, e, OracleTypes.STRUCT); pstmt.executeQuery(); System.out.println("insert done"); pstmt.close(); // line 52 // Select the contents of the employee_table // line 54 Statement s = conn.createStatement(); OracleResultSet rs = (OracleResultSet) s.executeQuery("SELECT * FROM employee_table"); // line 57 // print the contents of the table // line 59 while(rs.next()) { EmployeeObj ee = (EmployeeObj) rs.getObject(1); System.out.println("EmpName: " + ee.empName + " EmpNo: " + ee.empNo); } // line 64 // close the result set, statement, and connection // line 66 rs.close(); s.close(); if (conn != null) { conn.close(); // line 72 } } }
Import needed java.* and oracle.* packages. Register the driver with the DriverManager.registerDriver() method and connect to the database with the getConnection() method. Use the database URL jdbc:oracle:oci8:@ and connect as user scott with password tiger. You can optionally enter a database name following the @ symbol.
Use the getTypeMap() method to get the type map associated with this connection. Use the map object's put() method to add the mapping of the SQL EMPLOYEE object to the EmployeeObj custom Java type.
Create a statement object and drop any pre-existing tables and types named EMPLOYEE_TABLE and EMPLOYEE.
Use SQL statements to:
EMPLOYEE object with employee name and employee number attributes
EMPLOYEE_TABLE) having a single EMPLOYEE column
Create a new EmployeeObj object (which is a SQLData object). Identify the schema name (SCOTT), SQL type name (EMPLOYEE), an employee name (George Jones) and an employee number (456). Note that the schema name is the same as the user name in the getConnection() call. If you change the user name, you must also change the schema name.
Prepare a statement to insert the new EMPLOYEE object into the employee table. The setObject() method indicates that the object will be inserted into the first index position and that the underlying type of the EMPLOYEE object is oracle.sql.STRUCT.
Select the contents of the EMPLOYEE_TABLE. Cast the results to an OracleResultSet so that you can retrieve the custom Java object data from it.
Iterate through the result set, getting the contents of the EMPLOYEE objects and printing the employee names and employee numbers.
Close the result set, statement, and connection objects.
This section describes a Java class, written by a user, that implements the CustomDatum and CustomDatumFactory interfaces. The custom Java class of type CustomDatum has a static getFactory() method that returns a CustomDatumFactory object. The JDBC driver uses the CustomDatumFactory object's create() method to return a CustomDatum instance. Note that instead of writing the custom Java class yourself, you can use the JPublisher utility to generate class definitions that implement the CustomDatum and CustomDatumFactory interfaces.
The following example illustrates a Java class definition that can be written by a user, given the SQL definition of an EMPLOYEE object.
The following SQL code defines the EMPLOYEE object. The EMPLOYEE object consists of the employee's name (EmpName) and the employee's associated number (EmpNo).
create type EMPLOYEE as object ( EmpName VARCHAR2(50), EmpNo INTEGER );
Below are the contents of the Employee.java file.
import java.math.BigDecimal; import java.sql.SQLException; import oracle.jdbc.driver.OracleConnection; import oracle.sql.CustomDatum; import oracle.sql.CustomDatumFactory; import oracle.sql.Datum; import oracle.sql.STRUCT; import oracle.sql.StructDescriptor; public class Employee implements CustomDatum, CustomDatumFactory // line 10 { static final Employee _employeeFactory = new Employee(null, null); //line 13 public static CustomDatumFactory getFactory() { return _employeeFactory; } // line 18 /* constructor */ // line 20 public Employee(String empName, BigDecimal empNo) { this.empName = empName; this.empNo = empNo; } // line 25 /* CustomDatum interface */ // line 27 public Datum toDatum(OracleConnection c) throws SQLException { StructDescriptor sd = StructDescriptor.createDescriptor("SCOTT.EMPLOYEE", c); Object [] attributes = { empName, empNo }; return new STRUCT(sd, c, attributes); } // line 36 /* CustomDatumFactory interface */ // line 38 public CustomDatum create(Datum d, int sqlType) throws SQLException { if (d == null) return null; System.out.println(d); Object [] attributes = ((STRUCT) d).getAttributes(); return new Employee((String) attributes[0], (BigDecimal) attributes[1]); } // line 49 /* fields */ public String empName; public BigDecimal empNo; }
As required, the Employee class implements the CustomDatum and CustomDatumFactory interfaces.
JPublisher defines a _employeeFactory object of class Employee, which will be returned by the getFactory() method and used to create new Employee objects. The getFactory() method returns an empty Employee object that you can use to create new Employee objects.
JPublisher defines the Employee Java class to correspond to the SQL EMPLOYEE object. JPublisher creates the Employee class with two attributes: an employee name of type java.lang.String and an employee number of type java.math.BigDecimal.
The toDatum() method of the CustomDatum interface transforms the EMPLOYEE SQL data into oracle.sql.* representation. To do this, toDatum() uses:
STRUCT descriptor that takes the schema name, the SQL object or "type" name, and the connection object as arguments
The toDatum() returns a STRUCT containing the STRUCT descriptor, the connection object and the object attributes into an oracle.sql.Datum.
The CustomDatumFactory interface specifies a create() method that is analogous to the constructor of your Employee custom Java class. The create() method takes the Datum object and the SQL type code of the Datum object and returns a CustomDatum instance.
According to the definition, the create() method returns null if the value of the Datum object is null. Otherwise, it returns an instance of the Employee object with the employee name and employee number attributes.
This code snippet presents a simple example of how you can use the Employee class that you created with JPublisher. The sample code creates a new Employee object, fills it with data, then inserts it into the database. The sample code then retrieves the Employee data from the database.
Except for some changes to the comments, the following sample is similar to the CustomDatumExample.java program in the Demo/samples/oci8/object-samples directory.
import java.sql.*; // line 1 import oracle.jdbc.driver.*; import oracle.sql.*; import java.math.BigDecimal; public class CustomDatumExample { public static void main(String args []) throws Exception { // Connect DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver ()); OracleConnection conn = (OracleConnection) DriverManager.getConnection("jdbc:oracle:oci8:@", "scott", "tiger"); // Create a Statement // line 18 Statement stmt = conn.createStatement (); try { stmt.execute ("drop table EMPLOYEE_TABLE"); stmt.execute ("drop type EMPLOYEE"); } catch (SQLException e) { // An error is raised if the table/type does not exist. Just ignore it. } // line 28 // Create and populate tables // line 30 stmt.execute ("CREATE TYPE EMPLOYEE AS " + " OBJECT(EmpName VARCHAR2(50),EmpNo INTEGER)"); stmt.execute ("CREATE TABLE EMPLOYEE_TABLE (ATTR1 EMPLOYEE)"); stmt.execute ("INSERT INTO EMPLOYEE_TABLE " + " VALUES (EMPLOYEE('Susan Smith', 123))"); // line 35 // Create a CustomDatum object // line 37 Employee e = new Employee("George Jones", new BigDecimal("456")); // Insert the CustomDatum object // line 40 PreparedStatement pstmt = conn.prepareStatement ("INSERT INTO employee_table VALUES (?)"); pstmt.setObject(1, e, OracleTypes.STRUCT); pstmt.executeQuery(); System.out.println("insert done"); pstmt.close(); // line 47 // Select now // line 49 Statement s = conn.createStatement(); OracleResultSet rs = (OracleResultSet) s.executeQuery("SELECT * FROM employee_table"); while(rs.next()) // line 54 { Employee ee = (Employee) rs.getCustomDatum(1, Employee.getFactory()); System.out.println("EmpName: " + ee.empName + " EmpNo: " + ee.empNo); } // line 58 rs.close(); s.close(); if (conn != null) { conn.close(); } } }
Import needed java.* and oracle.* packages. Register the driver with the DriverManager.registerDriver() method and connect to the database with the getConnection() method. Use the database URL jdbc:oracle:oci8:@ and connect as user system with password manager. You can optionally enter a database name following the @ symbol.
Create a statement object and drop any pre-existing tables and types named EMPLOYEE_TABLE and EMPLOYEE.
Use SQL statements to:
Employee object with employee name and employee number attributes
EMPLOYEE column
Create a new Employee object (which is a CustomDatum object) and define an employee name and employee number for it.
Prepare a statement to insert the new Employee object into the database. The setObject() method indicates that the object will be inserted into the first index position and that the underlying type of the Employee object is oracle.sql.STRUCT.
Select the contents of the employee_table. Cast the results to an OracleResultSet so that the getCustomDatum() method can be used on it.
Iterate through the result set, getting the contents of the Employee objects and printing the employee names and employee numbers.
Close the result set, statement, and connection objects.