+ All Categories
Home > Documents > Web viewIf you want to call a Java method that is not static, then you must specify the keyword...

Web viewIf you want to call a Java method that is not static, then you must specify the keyword...

Date post: 13-Feb-2018
Category:
Upload: vuhanh
View: 219 times
Download: 0 times
Share this document with a friend
31
If you want to call a Java method that is not static, then you must specify the keyword MEMBER in its call specification. If you want to call a static Java method, then you must specify the keyword STATIC in its call specification. Note: To invoke a Java constructor from SQL, you must wrap calls to it in a static method and declare the corresponding call specification as a STATIC member of the object type. 1
Transcript

If you want to call a Java method that is not static, then you must specify the keyword MEMBER in its call specification. If you want to call a static Java method, then you must specify the keyword STATIC in its call specification.

Note: To invoke a Java constructor from SQL, you must wrap calls to it in a static method and declare the corresponding call specification as a STATIC member of the object type.

1

Implementing Object Type MethodsAssume you decide to drop the top-level call specifications wages and raise_sal and redeclare them as methods of the object type Employee. In an object type specification, all methods must be declared after the attributes. The body of the object type is not required, because the specification declares only attributes and call specifications. The Employee object type can be re-created as follows:

CREATE TYPE Employee AS OBJECT(empno NUMBER(4),ename VARCHAR2(10),job VARCHAR2(9),mgr NUMBER(4),hiredate DATE,sal NUMBER(7,2),comm NUMBER(7,2),deptno REF DepartmentMEMBER FUNCTION wages RETURN NUMBER AS LANGUAGE JAVA NAME 'Paymaster.wages() return java.math.BigDecimal',MEMBER PROCEDURE raise_sal (r NUMBER) AS LANGUAGE JAVA NAME 'Paymaster.raiseSal(java.math.BigDecimal)');

Then, you revise Paymaster accordingly. You need not pass an array to raiseSal(), because the SQL parameter SELF corresponds directly to the Java parameter this, even when SELF is declared as IN OUT, which is the default for procedures.

import java.sql.*;import java.io.*;import oracle.sql.*;import oracle.jdbc.*;import oracle.oracore.*;import oracle.jdbc2.*;import java.math.*;public class Paymaster implements SQLData{ // Implement the attributes and operations for this type. private BigDecimal empno; private String ename; private String job; private BigDecimal mgr; private Date hiredate; private BigDecimal sal; private BigDecimal comm; private Ref dept; public BigDecimal wages(){ BigDecimal pay = sal; if (comm != null) pay = pay.add(comm); return pay; }

public void raiseSal(BigDecimal amount) { // For SELF/this, even when IN OUT, no array is needed. sal = sal.add(amount);}

2

// Implement SQLData interface. String sql_type; public String getSQLTypeName() throws SQLException{ return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException{ sql_type = typeName; empno = stream.readBigDecimal(); ename = stream.readString(); job = stream.readString(); mgr = stream.readBigDecimal(); hiredate = stream.readDate(); sal = stream.readBigDecimal(); comm = stream.readBigDecimal(); dept = stream.readRef();}

public void writeSQL(SQLOutput stream) throws SQLException{ stream.writeBigDecimal(empno); stream.writeString(ename); stream.writeString(job); stream.writeBigDecimal(mgr); stream.writeDate(hiredate); stream.writeBigDecimal(sal); stream.writeBigDecimal(comm); stream.writeRef(dept);}}

Later, you decide to drop the top-level call specs wages and raise_sal and redeclare them as methods of object type Employee. In an object type spec, all methods must be declared after the attributes. The object type body is unnecessary because the spec declares only attributes and call specs.

CREATE TYPE Employee AS OBJECT ( empno NUMBER(4), ename VARCHAR2(10), job VARCHAR2(9), mgr NUMBER(4), hiredate DATE, sal NUMBER(7,2), comm NUMBER(7,2), deptno REF Department MEMBER FUNCTION wages RETURN NUMBER AS LANGUAGE JAVA NAME 'Paymaster.wages() return java.math.BigDecimal', MEMBER PROCEDURE raise_sal (r NUMBER) AS LANGUAGE JAVA NAME 'Paymaster.raiseSal(java.math.BigDecimal)' );

Then, you revise class Paymaster accordingly. You need not pass an array to method raiseSal because the SQL parameter SELF corresponds directly to the Java parameter this—even when SELF is declared as IN OUT (the default for procedures).import java.sql.*;import java.io.*;

3

import oracle.sql.*;import oracle.jdbc.*;import oracle.oracore.*;import oracle.jdbc2.*;import java.math.*;public class Paymaster implements SQLData { // Implement the attributes and operations for this type. private BigDecimal empno; private String ename; private String job; private BigDecimal mgr; private Date hiredate; private BigDecimal sal; private BigDecimal comm; private Ref dept; public BigDecimal wages() { BigDecimal pay = sal; if (comm != null) pay = pay.add(comm); return pay; }

public void raiseSal(BigDecimal amount) { // For SELF/this, even when IN OUT, no array is needed. sal = sal.add(amount); } // Implement SQLData interface.

String sql_type; public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException { sql_type = typeName; empno = stream.readBigDecimal(); ename = stream.readString(); job = stream.readString(); mgr = stream.readBigDecimal(); hiredate = stream.readDate(); sal = stream.readBigDecimal(); comm = stream.readBigDecimal(); dept = stream.readRef(); }

public void writeSQL(SQLOutput stream) throws SQLException { stream.writeBigDecimal(empno); stream.writeString(ename); stream.writeString(job); stream.writeBigDecimal(mgr); stream.writeDate(hiredate); stream.writeBigDecimal(sal); stream.writeBigDecimal(comm);

4

stream.writeRef(dept); } }

5

Object-Type Inheritance

Object-type inheritance allows a new object type to be created by extending another object type. The new object type is then a subtype of the object type from which it extends. The subtype automatically inherits all the attributes and methods defined in the supertype. The subtype can add attributes and methods and overload or override methods inherited from the supertype.Object-type inheritance introduces substitutability. Substitutability is the ability of a slot declared to hold a value of type T in addition to any subtype of type T. Oracle JDBC drivers handle substitutability transparently.A database object is returned with its most specific type without losing information. For example, if the STUDENT_T object is stored in a PERSON_T slot, Oracle JDBC driver returns a Java object that represents the STUDENT_T object.

Creating SubtypesCreate custom object classes if you want to have Java classes that explicitly correspond to the Oracle object types. If you have a hierarchy of object types, you may want a corresponding hierarchy of Java classes.The most common way to create a database subtype in JDBC is to run a SQL CREATE TYPE command using the execute method of the java.sql.Statement interface. For example, you want to create a type inheritance hierarchy for:PERSON_T | STUDENT_T | PARTTIMESTUDENT_TThe JDBC code for this can be as follows:Statement s = conn.createStatement();s.execute ("CREATE TYPE Person_T (SSN NUMBER, name VARCHAR2(30), address VARCHAR2(255))");s.execute ("CREATE TYPE Student_T UNDER Person_t (deptid NUMBER, major VARCHAR2(100))");s.execute ("CREATE TYPE PartTimeStudent_t UNDER Student_t (numHours NUMBER)");In the following code, the foo member procedure in type ST is overloaded and the member procedure print overwrites the copy it inherits from type T.CREATE TYPE T AS OBJECT (..., MEMBER PROCEDURE foo(x NUMBER), MEMBER PROCEDURE Print(), ... NOT FINAL;

CREATE TYPE ST UNDER T (..., MEMBER PROCEDURE foo(x DATE), <-- overload "foo" OVERRIDING MEMBER PROCEDURE Print(), <-- override "print" STATIC FUNCTION bar(...) ... ... );Once the subtypes have been created, they can be used as both columns of a base table as well as attributes of a object type.See Also:Oracle Database Object-Relational Developer's Guide

6

Implementing Customized Classes for SubtypesIn most cases, a customized Java class represents a database object type. When you create a customized Java class for a subtype, the Java class can either mirror the database object type hierarchy or not.You can use either the ORAData or SQLData solution in creating classes to map to the hierarchy of object types.

Use of ORAData for Type Inheritance HierarchyCustomized mapping where Java classes implement the oracle.sql.ORAData interface is the recommended mapping. ORAData mapping requires the JDBC application to implement the ORAData and ORADataFactory interfaces. The class implementing the ORADataFactory interface contains a factory method that produces objects. Each object represents a database object.The hierarchy of the class implementing the ORAData interface can mirror the database object type hierarchy. For example, the Java classes mapping to PERSON_T and STUDENT_T are as follows:Person.java using ORADataCode for the Person.java class which implements the ORAData and ORADataFactory interfaces:class Person implements ORAData, ORADataFactory { static final Person _personFactory = new Person();

public NUMBER ssn; public CHAR name; public CHAR address;

public static ORADataFactory getORADataFactory() { return _personFactory; }

public Person () {}

public Person(NUMBER ssn, CHAR name, CHAR address) { this.ssn = ssn; this.name = name; this.address = address; }

public Datum toDatum(OracleConnection c) throws SQLException { StructDescriptor sd = StructDescriptor.createDescriptor("SCOTT.PERSON_T", c); Object [] attributes = { ssn, name, address }; return new STRUCT(sd, c, attributes); }

public ORAData create(Datum d, int sqlType) throws SQLException { if (d == null) return null; Object [] attributes = ((STRUCT) d).getOracleAttributes(); return new Person((NUMBER) attributes[0],

7

(CHAR) attributes[1], (CHAR) attributes[2]); } }Student.java extending Person.javaCode for the Student.java class, which extends the Person.java class:class Student extends Person { static final Student _studentFactory = new Student ();

public NUMBER deptid; public CHAR major;

public static ORADataFactory getORADataFactory() { return _studentFactory; }

public Student () {}

public Student (NUMBER ssn, CHAR name, CHAR address, NUMBER deptid, CHAR major) { super (ssn, name, address); this.deptid = deptid; this.major = major; }

public Datum toDatum(OracleConnection c) throws SQLException { StructDescriptor sd = StructDescriptor.createDescriptor("SCOTT.STUDENT_T", c); Object [] attributes = { ssn, name, address, deptid, major }; return new STRUCT(sd, c, attributes); }

public CustomDatum create(Datum d, int sqlType) throws SQLException { if (d == null) return null; Object [] attributes = ((STRUCT) d).getOracleAttributes(); return new Student((NUMBER) attributes[0], (CHAR) attributes[1], (CHAR) attributes[2], (NUMBER) attributes[3], (CHAR) attributes[4]); } }Customized classes that implement the ORAData interface do not have to mirror the database object type hierarchy. For example, you could have declared the Student class without a superclass. In this case, Student would contain fields to hold the inherited attributes from PERSON_T as well as the attributes declared by STUDENT_T.

8

ORADataFactory ImplementationThe JDBC application uses the factory class in querying the database to return instances of Person or its subclasses, as in the following example:ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { Object s = rset.getORAData (1, PersonFactory.getORADataFactory()); ... } A class implementing the ORADataFactory interface should be able to produce instances of the associated custom object type, as well as instances of any subtype, or at least all the types you expect to support.In the following example, the PersonFactory.getORADataFactory method returns a factory that can handle PERSON_T, STUDENT_T, and PARTTIMESTUDENT_T objects, by returning person, student, or parttimestudent Java instances.class PersonFactory implements ORADataFactory { static final PersonFactory _factory = new PersonFactory ();

public static ORADataFactory getORADataFactory() { return _factory; }

public ORAData create(Datum d, int sqlType) throws SQLException { STRUCT s = (STRUCT) d; if (s.getSQLTypeName ().equals ("SCOTT.PERSON_T")) return Person.getORADataFactory ().create (d, sqlType); else if (s.getSQLTypeName ().equals ("SCOTT.STUDENT_T")) return Student.getORADataFactory ().create(d, sqlType); else if (s.getSQLTypeName ().equals ("SCOTT.PARTTIMESTUDENT_T")) return ParttimeStudent.getORADataFactory ().create(d, sqlType); else return null; } }The following example assumes a table tabl1, such as the following:CREATE TABLE tabl1 (idx NUMBER, person PERSON_T); INSERT INTO tabl1 VALUES (1, PERSON_T (1000, 'Scott', '100 Oracle Parkway')); INSERT INTO tabl1 VALUES (2, STUDENT_T (1001, 'Peter', '200 Oracle Parkway', 101, 'CS')); INSERT INTO tabl1 VALUES (3, PARTTIMESTUDENT_T (1002, 'David', '300 Oracle Parkway', 102, 'EE'));

9

Use of SQLData for Type Inheritance HierarchyThe customized classes that implement the java.sql.SQLData interface can mirror the database object type hierarchy. The readSQL and writeSQL methods of a subclass typically call the corresponding superclass methods to read or write the superclass attributes before reading or writing the subclass attributes. For example, the Java classes mapping to PERSON_T and STUDENT_T are as follows:Person.java using SQLDataCode for the Person.java class, which implements the SQLData interface:import java.sql.*;

public class Person implements SQLData { private String sql_type; public int ssn; public String name; public String address;

public Person () {}

public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException { sql_type = typeName; ssn = stream.readInt(); name = stream.readString(); address = stream.readString(); }

public void writeSQL(SQLOutput stream) throws SQLException { stream.writeInt (ssn); stream.writeString (name); stream.writeString (address); } }Student.java extending Student.javaCode for the Student.java class, which extends the Person.java class:import java.sql.*;

public class Student extends Person { private String sql_type; public int deptid; public String major;

public Student () { super(); }

public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException

10

{ super.readSQL (stream, typeName); // read supertype attributes sql_type = typeName; deptid = stream.readInt(); major = stream.readString(); }

public void writeSQL(SQLOutput stream) throws SQLException { super.writeSQL (stream); // write supertype // attributes stream.writeInt (deptid); stream.writeString (major); } }Although not required, it is recommended that the customized classes, which implement the SQLData interface, mirror the database object type hierarchy. For example, you could have declared the Student class without a superclass. In this case, Student would contain fields to hold the inherited attributes from PERSON_T as well as the attributes declared by STUDENT_T.Student.java using SQLDataCode for the Student.java class, which does not extend the Person.java class, but implements the SQLData interface directly:import java.sql.*;

public class Student implements SQLData { private String sql_type;

public int ssn; public String name; public String address; public int deptid; public String major;

public Student () {}

public String getSQLTypeName() throws SQLException { return sql_type; }

public void readSQL(SQLInput stream, String typeName) throws SQLException { sql_type = typeName; ssn = stream.readInt(); name = stream.readString(); address = stream.readString(); deptid = stream.readInt(); major = stream.readString(); }

public void writeSQL(SQLOutput stream) throws SQLException { stream.writeInt (ssn);

11

stream.writeString (name); stream.writeString (address); stream.writeInt (deptid); stream.writeString (major); } }

12

JPublisher UtilityEven though you can manually create customized classes that implement the SQLData, ORAData, and ORADataFactory interfaces, it is recommended that you use Oracle JPublisher to automatically generate these classes. The customized classes generated by Oracle JPublisher that implement the SQLData, ORAData, and ORADataFactory interfaces, can mirror the inheritance hierarchy.

Retrieving Subtype ObjectsIn a typical JDBC application, a subtype object is returned as one of the following: A query result A PL/SQL OUT parameter A type attributeYou can use either the default mapping or the SQLData mapping or the ORAData mapping to retrieve a subtype.Using Default MappingBy default, a database object is returned as an instance of the oracle.sql.STRUCT class. This instance may represent an object of either the declared type or subtype of the declared type. If the STRUCT class represents a subtype object in the database, then it contains the attributes of its supertype as well as those defined in the subtype.Oracle JDBC driver returns database objects in their most specific type. The JDBC application can use the getSQLTypeName method of the STRUCT class to determine the SQL type of the STRUCT object. The following code shows this:// tab1.person column can store PERSON_T, STUDENT_T and PARTIMESTUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { oracle.sql.STRUCT s = (oracle.sql.STRUCT) rset.getObject(1); if (s != null) System.out.println (s.getSQLTypeName()); // print out the type name which // may be SCOTT.PERSON_T, SCOTT.STUDENT_T or SCOTT.PARTTIMESTUDENT_T}Using SQLData MappingWith SQLData mapping, the JDBC driver returns the database object as an instance of the class implementing the SQLData interface.To use SQLData mapping in retrieving database objects, do the following:1. Implement the container classes that implement the SQLData interface for the desired object types.2. Populate the connection type map with entries that specify what custom Java type corresponds to each Oracle object type.3. Use the getObject method to access the SQL object values.The JDBC driver checks the type map for an entry match. If one exists, then the driver returns the database object as an instance of the class implementing the SQLData interface.The following code shows the whole SQLData customized mapping process:// The JDBC application developer implements Person.java for PERSON_T, // Student.java for STUDENT_T // and ParttimeStudent.java for PARTTIMESTUDEN_T.

Connection conn = ...; // make a JDBC connection

// obtains the connection typemap java.util.Map map = conn.getTypeMap ();

13

// populate the type map map.put ("SCOTT.PERSON_T", Class.forName ("Person")); map.put ("SCOTT.STUDENT_T", Class.forName ("Student")); map.put ("SCOTT.PARTTIMESTUDENT_T", Class.forName ("ParttimeStudent"));

// tab1.person column can store PERSON_T, STUDENT_T and PARTTIMESTUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { // "s" is instance of Person, Student or ParttimeStudent Object s = rset.getObject(1);

if (s != null) { if (s instanceof Person) System.out.println ("This is a Person"); else if (s instanceof Student) System.out.println ("This is a Student"); else if (s instanceof ParttimeStudent) System.out.pritnln ("This is a PartimeStudent"); else System.out.println ("Unknown type"); } }The JDBC drivers check the connection type map for each call to the following: getObject method of the java.sql.ResultSet and java.sql.CallableStatement interfaces getAttribute method of the java.sql.Struct interface getArray method of the java.sql.Array interface getValue method of the oracle.sql.REF interfaceUsing ORAData MappingWith ORAData mapping, the JDBC driver returns the database object as an instance of the class implementing the ORAData interface.Oracle JDBC driver needs to be informed of what Java class is mapped to the Oracle object type. The following are the two ways to inform Oracle JDBC drivers: The JDBC application uses the getORAData(int idx, ORADataFactory f) method to access database objects. The second parameter of the getORAData method specifies an instance of the factory class that produces the customized class. The getORAData method is available in the OracleResultSet and OracleCallableStatement classes. The JDBC application populates the connection type map with entries that specify what custom Java type corresponds to each Oracle object type. The getObject method is used to access the Oracle object values.The second approach involves the use of the standard getObject method. The following code example demonstrates the first approach:// tab1.person column can store both PERSON_T and STUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { Object s = rset.getORAData (1, PersonFactory.getORADataFactory()); if (s != null) {

14

if (s instanceof Person) System.out.println ("This is a Person"); else if (s instanceof Student) System.out.println ("This is a Student"); else if (s instanceof ParttimeStudent) System.out.pritnln ("This is a PartimeStudent"); else System.out.println ("Unknown type"); } }Creating Subtype ObjectsThere are cases where JDBC applications create database subtype objects with JDBC drivers. These objects are sent either to the database as bind variables or are used to exchange information within the JDBC application.With customized mapping, the JDBC application creates either SQLData- or ORAData-based objects, depending on the approach you choose, to represent database subtype objects. With default mapping, the JDBC application creates STRUCT objects to represent database subtype objects. All the data fields inherited from the supertype as well as all the fields defined in the subtype must have values. The following code demonstrates this:Connection conn = ... // make a JDBC connection StructDescriptor desc = StructDescriptor.createDescriptor ("SCOTT.PARTTIMESTUDENT", conn); Object[] attrs = { new Integer(1234), "Scott", "500 Oracle Parkway", // data fields defined in // PERSON_T new Integer(102), "CS", // data fields defined in // STUDENT_T new Integer(4) // data fields defined in // PARTTIMESTUDENT_T }; STRUCT s = new STRUCT (desc, conn, attrs);s is initialized with data fields inherited from PERSON_T and STUDENT_T, and data fields defined in PARTTIMESTUDENT_T.Sending Subtype ObjectsIn a typical JDBC application, a Java object that represents a database object is sent to the databases as one of the following: A data manipulation language (DML) bind variable A PL/SQL IN parameter An object type attribute valueThe Java object can be an instance of the STRUCT class or an instance of the class implementing either the SQLData or ORAData interface. Oracle JDBC driver will convert the Java object into the linearized format acceptable to the database SQL engine. Binding a subtype object is the same as binding a standard object.Accessing Subtype Data FieldsWhile the logic to access subtype data fields is part of the customized class, this logic for default mapping is defined in the JDBC application itself. The database objects are returned as instances of the oracle.sql.STRUCT class. The JDBC application needs to call one of the following access methods in the STRUCT class to access the data fields: Object[] getAttribute() oracle.sql.Datum[] getOracleAttribute()Subtype Data Fields from the getAttribute Method

15

The getAttribute method of the java.sql.Struct interface is used in JDBC 2.0 to access object data fields. This method returns a java.lang.Object array, where each array element represents an object attribute. You can determine the individual element type by referencing the corresponding attribute type in the JDBC conversion matrix, as listed in Table 4-1. For example, a SQL NUMBER attribute is converted to a java.math.BigDecimal object. The getAttribute method returns all the data fields defined in the supertype of the object type as well as data fields defined in the subtype. The supertype data fields are listed first followed by the subtype data fields.Subtype Data Fields from the getOracleAttribute MethodThe getOracleAttribute method is an Oracle extension method and is more efficient than the getAttribute method. The getOracleAttribute method returns an oracle.sql.Datum array to hold the data fields. Each element in the oracle.sql.Datum array represents an attribute. You can determine the individual element type by referencing the corresponding attribute type in the Oracle conversion matrix, as listed in Table 4-1. For example, a SQL NUMBER attribute is converted to an oracle.sql.NUMBER object. The getOracleAttribute method returns all the attributes defined in the supertype of the object type, as well as attributes defined in the subtype. The supertype data fields are listed first followed by the subtype data fields.The following code shows the use of the getAttribute method:// tab1.person column can store PERSON_T, STUDENT_T and PARTIMESTUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { oracle.sql.STRUCT s = (oracle.sql.STRUCT) rset.getObject(1); if (s != null) { String sqlname = s.getSQLTypeName();

Object[] attrs = s.getAttribute();

if (sqlname.equals ("SCOTT.PERSON") { System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue()); System.out.println ("name="+((String)attrs[1])); System.out.println ("address="+((String)attrs[2])); } else if (sqlname.equals ("SCOTT.STUDENT")) { System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue()); System.out.println ("name="+((String)attrs[1])); System.out.println ("address="+((String)attrs[2])); System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue()); System.out.println ("major="+((String)attrs[4])); } else if (sqlname.equals ("SCOTT.PARTTIMESTUDENT")) { System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue()); System.out.println ("name="+((String)attrs[1])); System.out.println ("address="+((String)attrs[2])); System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue()); System.out.println ("major="+((String)attrs[4])); System.out.println ("numHours="+((BigDecimal)attrs[5]).intValue()); }

16

else throw new Exception ("Invalid type name: "+sqlname); } } rset.close (); stmt.close (); conn.close ();

17

Inheritance Metadata MethodsOracle JDBC drivers provide a set of metadata methods to access inheritance properties. The inheritance metadata methods are defined in the oracle.sql.StructDescriptor and oracle.jdbc.StructMetaData classes.The StructMetaData class provides inheritance metadata methods for subtype attributes. The getMetaData method of the StructDescriptor class returns an instance of StructMetaData of the type. The StructMetaData class contains the following inheritance metadata methods:Using JPublisher to Create Custom Object ClassesA convenient way to create custom object classes, as well as other kinds of custom Java classes, is to use the Oracle JPublisher utility. It generates a full definition for a custom Java class, which you can instantiate to hold the data from an Oracle object. JPublisher-generated classes include methods to convert data from SQL to Java and from Java to SQL, as well as getter and setter methods for the object attributes.This section covers the following topics: JPublisher Functionality JPublisher Type Mappings See Also:Oracle Database JPublisher User's Guide.JPublisher FunctionalityYou can direct JPublisher to create custom object classes that implement either the SQLData interface or the ORAData interface, according to how you set the JPublisher type mappings.If you use the ORAData interface, then JPublisher will also create a custom reference class to map to object references for the Oracle object type. If you use the SQLData interface, then JPublisher will not produce a custom reference class. You would use standard java.sql.Ref instances instead.If you want additional functionality, you can subclass the custom object class and add features as desired. When you run JPublisher, there is a command-line option for specifying both a generated class name and the name of the subclass you will implement. For the SQL-Java mapping to work properly, JPublisher must know the subclass name, which is incorporated into some of the functionality of the generated class.Note:Hand-editing the JPublisher-generated class, instead of subclassing it, is not recommended. If you hand-edit this class and later have to re-run JPublisher for some reason, you would have to re-implement your changes.JPublisher Type MappingsJPublisher offers various choices for how to map user-defined types and their attribute types between SQL and Java. This section lists categories of SQL types and the mapping options available for each category.Categories of SQL TypesJPublisher categorizes SQL types into the following groups, with corresponding JPublisher options as specifies: User-defined types (UDT)This includes Oracle objects, references, and collections. You use the JPublisher -usertypes option to specify the type-mapping implementation for UDTs, either a standard SQLData implementation or an Oracle-specific ORAData implementation. Numeric typesThis includes anything stored in the database as the NUMBER SQL type. You use the JPublisher -numbertypes option to specify type-mapping for numeric types. Large object (LOB) typesThis includes the SQL types, BLOB and CLOB. You use the JPublisher -lobtypes option to specify type-mapping for LOB types. Built-in types

18

This includes anything stored in the database as a SQL type not covered by the preceding categories. For example, CHAR, VARCHAR2, LONG, and RAW. You use the JPublisher -builtintypes option to specify type-mapping for built-in types.Type-Mapping ModesJPublisher defines the following type-mapping modes, two of which apply to numeric types only: JDBC mapping (setting jdbc)Uses standard default mappings between SQL types and Java native types. For a custom object class, uses a SQLData implementation. Oracle mapping (setting oracle)Uses corresponding oracle.sql types to map to SQL types. For a custom object, reference, or collection class, uses a ORAData implementation. Object-JDBC mapping (setting objectjdbc)Is an extension of the JDBC mapping. Where relevant, object-JDBC mapping uses numeric object types from the standard java.lang package, such as java.lang.Integer, Float, and Double, instead of primitive Java types, such as int, float, and double. The java.lang types are nullable, while the primitive types are not. BigDecimal mapping (setting bigdecimal)Uses java.math.BigDecimal to map to all numeric attributes. This is appropriate if you are dealing with large numbers but do not want to map to the oracle.sql.NUMBER class.Note:Using BigDecimal mapping can significantly degrade performance.Mapping the Oracle object type to JavaUse the JPublisher -usertypes option to determine how JPublisher will implement the custom Java class that corresponds to a Oracle object type: A setting of -usertypes=oracle, which is the default setting, instructs JPublisher to create a ORAData implementation for the custom object class. This will also result in JPublisher producing a ORAData implementation for the corresponding custom reference class. A setting of -usertypes=jdbc instructs JPublisher to create a SQLData implementation for the custom object class. No custom reference class can be created. You must use java.sql.Ref or oracle.sql.REF for the reference type.Note:You can also use JPublisher with a -usertypes=oracle setting in creating ORAData implementations to map SQL collection types. The -usertypes=jdbc setting is not valid for mapping SQL collection types. The SQLData interface is intended only for mapping Oracle object types.Mapping Attribute Types to JavaIf you do not specify mappings for the attribute types of the Oracle object type, then JPublisher uses the following defaults: For numeric attribute types, the default mapping is object-JDBC. For LOB attribute types, the default mapping is Oracle. For built-in type attribute types, the default mapping is JDBC.If you want alternate mappings, then use the -numbertypes, -lobtypes, and -builtintypes options, as necessary, depending on the attribute types you have and the mappings you desire.If an attribute type is itself an Oracle object type, then it will be mapped according to the -usertypes setting.Important:Be aware that if you specify an SQLData implementation for the custom object class and want the code to be portable, then you must be sure to use portable mappings for the attribute types. The defaults for numeric types and built-in types are portable, but for LOB types you must specify -lobtypes=jdbc.Summary of SQL Type Categories and Mapping Settings

19

Table 13-1 summarizes JPublisher categories for SQL types, the mapping settings relevant for each category, and the default settings.Table 13-1 JPublisher SQL Type Categories, Supported Settings, and DefaultsSQL Type Category JPublisher Mapping Option Mapping Settings DefaultUDT types -usertypes oracle, jdbc oraclenumeric types -numbertypes oracle, jdbc, objectjdbc, bigdecimal objectjdbcLOB types -lobtypes oracle, jdbc oraclebuilt-in types -builtintypes oracle, jdbc jdbc

Describing an Object TypeOracle JDBC includes functionality to retrieve information about a structured object type regarding its attribute names and types. This is similar conceptually to retrieving information from a result set about its column names and types, and in fact uses an almost identical method.

Functionality for Getting Object MetadataThe oracle.sql.StructDescriptor class includes functionality to retrieve metadata about a structured object type. The StructDescriptor class has a getMetaData method with the same functionality as the standard getMetaData method available in result set objects. It returns a set of attribute information, such as attribute names and types. Call this method on a StructDescriptor object to get metadata about the Oracle object type that the StructDescriptor object describes.The signature of the StructDescriptor class getMetaData method is the same as the signature specified for getMetaData in the standard ResultSet interface. The signature is as follows:ResultSetMetaData getMetaData() throws SQLExceptionHowever, this method actually returns an instance of oracle.jdbc.StructMetaData, a class that supports structured object metadata in the same way that the standard java.sql.ResultSetMetaData interface specifies support for result set metadata.The following method is also supported by StructMetaData:String getOracleColumnClassName(int column) throws SQLExceptionThis method returns the fully qualified name of the oracle.sql.Datum subclass whose instances are manufactured if the OracleResultSet class getOracleObject method is called to retrieve the value of the specified attribute. For example, oracle.sql.NUMBER.To use the getOracleColumnClassName method, you must cast the ResultSetMetaData object, which that was returned by the getMetaData method, to StructMetaData. Note:In all the preceding method signatures, column is something of a misnomer. Where you specify a value of 4 for column, you really refer to the fourth attribute of the object.Steps for Retrieving Object MetadataUse the following steps to obtain metadata about a structured object type:1. Create or acquire a StructDescriptor instance that describes the relevant structured object type.2. Call the getMetaData method on the StructDescriptor instance.3. Call the metadata getter methods, getColumnName, getColumnType, and getColumnTypeName, as desired.Note:If one of the structured object attributes is itself a structured object, repeat steps 1 through 3.ExampleThe following method shows how to retrieve information about the attributes of a structured object type. This includes the initial step of creating a StructDescriptor instance.// // Print out the ADT's attribute names and types //

20

void getAttributeInfo (Connection conn, String type_name) throws SQLException { // get the type descriptor StructDescriptor desc = StructDescriptor.createDescriptor (type_name, conn);

// get type metadata ResultSetMetaData md = desc.getMetaData ();

// get # of attrs of this type int numAttrs = desc.length ();

// temporary buffers String attr_name; int attr_type; String attr_typeName;

System.out.println ("Attributes of "+type_name+" :"); for (int i=0; i<numAttrs; i++) { attr_name = md.getColumnName (i+1); attr_type = md.getColumnType (i+1); System.out.println (" index"+(i+1)+" name="+attr_name+" type="+attr_type);

// drill down nested object if (attrType == OracleTypes.STRUCT) { attr_typeName = md.getColumnTypeName (i+1);

// recursive calls to print out nested object metadata getAttributeInfo (conn, attr_typeName); } } }

http://sungur.wordpress.com/2009/03/29/pairing-java-objects-with-oracle-types/

21

http://betteratoracle.com/posts/31-passing-record-types-between-oracle-and-java

Passing Record Types between Oracle and JavaRelated to the post on on passing arrays between java and oracle, someone asked me how to pass record types between Java and Oracle. Largely the same approach is used, but it is different enough to warrant an example.First, create the record type you wish to use:create or replace type rectype as object(col1 varchar2(10),col2 varchar2(10));/Then create a procedure or function to send it to. In this case, I have a procedure that simply copies the passed in record into an output record, which is enough to prove the values are being passed in and out of the procedure correctly:create or replace procedure p_rec (v1 rectype, v2 out rectype)isbegin v2 := v1;end;/That is all you need on the Oracle side, so the tricky bit, is writing the Java code to call this procedure:import oracle.jdbc.*;import oracle.sql.ArrayDescriptor;import oracle.sql.ARRAY;import oracle.sql.StructDescriptor;import oracle.sql.STRUCT;import oracle.jdbc.OracleTypes;import java.sql.*;

public class Rec {

public static void main(String[] args) throws ClassNotFoundException, SQLException { DriverManager.registerDriver (new oracle.jdbc.OracleDriver());

String url = "jdbc:oracle:thin:@//localhost:1521/local11gr2.world";

Connection conn = DriverManager.getConnection(url,"sodonnel","sodonnel");

conn.setAutoCommit(false);

// Create descriptors for each Oracle collection type required StructDescriptor recDescriptor = StructDescriptor.createDescriptor("RECTYPE",conn);

// create a callable statement to make the call to the proc CallableStatement stmt = conn.prepareCall("{ call p_rec(?, ?) }");

// In java, you stage the values for each field in the Oracle record in an array

22

Object[] java_record_array = new Object[2]; Object[] return_record_array = new Object[2];

// put some values in the array

java_record_array[0] = "col1"; java_record_array[1] = "col2";

// cast the java arrays into the Oracle record type for the input record STRUCT oracle_record = new STRUCT(recDescriptor, conn, java_record_array); // This struct is used to hold the return record type STRUCT output_oracle_record;

// Bind the input record stmt.setObject(1, oracle_record);

// register the output parameter stmt.registerOutParameter(2, OracleTypes.STRUCT, "RECTYPE");

stmt.execute();

// get the returned record from the callable statement - note the cast on the stmt handle output_oracle_record = ((OracleCallableStatement)stmt).getSTRUCT(2);

// finally cast the Oracle struct back into a Java array return_record_array = output_oracle_record.getAttributes();

// Show the results: System.out.println("First Object is now "+return_record_array[0]+" and "+return_record_array[1]); }}That is all there is too it. If I get some more free time, I will have a go at passing an array of records to a procedure, which I imagine is a combination of this code and the code to pass arrays to a procedure.

http://books.google.lv/books?id=MsEK0HJh2VAC&pg=PA104&lpg=PA104&dq=Java+and+Oracle+Object+Types&source=bl&ots=1IEULf_zkj&sig=OwfO-jyUVxy83cdG4-5NMsN35Cg&hl=lv&sa=X&ei=GoNfVOmGCtbtaPbYgOgO&ved=0CHAQ6AEwCQ#v=onepage&q=Java%20and%20Oracle%20Object%20Types&f=false

http://books.google.lv/books?id=T0GvgQYG070C&pg=PA523&lpg=PA523&dq=Java+and+Oracle+Object+Types&source=bl&ots=ggX_gTQMYY&sig=i-7gN4WXk5Htcs2mVcUTABZ5KKI&hl=lv&sa=X&ei=zoNfVOS5JsSfPZrhgZAJ&ved=0CB0Q6AEwADgK#v=onepage&q=Java%20and%20Oracle%20Object%20Types&f=false

23

http://books.google.lv/books?id=9MsOpXrElhUC&pg=PA324&lpg=PA324&dq=Java+and+Oracle+Object+Types&source=bl&ots=mDtnTICKPm&sig=jSO7vymOH2OQXGrH_RmVAe4IHY4&hl=lv&sa=X&ei=zoNfVOS5JsSfPZrhgZAJ&ved=0CGMQ6AEwCDgK#v=onepage&q=Java%20and%20Oracle%20Object%20Types&f=false

http://books.google.lv/books?id=jVrtv-8h2ncC&pg=PA497&lpg=PA497&dq=Java+and+Oracle+Object+Types&source=bl&ots=q7oWn5YN13&sig=ekfw0iCiSDEvJG3sXM_Xzayao_c&hl=lv&sa=X&ei=zoNfVOS5JsSfPZrhgZAJ&ved=0CGgQ6AEwCTgK#v=onepage&q=Java%20and%20Oracle%20Object%20Types&f=false

24

25


Recommended