この章では、JPublisherにより生成されるクラス、インタフェースおよびサブクラスについて説明します。この章の内容は、次のとおりです。
Java Database Connectivity(JDBC)を介してコールされるストアド・プロシージャでは、通常のJavaメソッドと同じ方法ではパラメータは渡されません。このことは、JPublisherで生成されるラッパー・メソッドをコールするときに記述するコードに影響します。
通常のJavaメソッドをコールすると、Javaオブジェクトであるパラメータはオブジェクト参照として渡されます。そのメソッドでオブジェクトを変更できます。
ただし、JDBCを介してストアド・プロシージャをコールすると、各パラメータのコピーがストアド・プロシージャに渡されます。プロシージャでパラメータを変更する場合は、変更されたパラメータのコピーがコール元に戻されます。このため、変更されたパラメータの前および後の値は別々のオブジェクトとなります。
JPublisherで生成されるラッパー・メソッドには、対応するストアド・プロシージャをコールするためのJDBC文が含まれます。CREATE TYPEまたはCREATE PACKAGE宣言で宣言されたストアド・プロシージャに対するパラメータには、使用可能なパラメータ・モード、IN、OUTおよびIN OUTがあります。IN OUTまたはOUTのパラメータは、新規に作成されたオブジェクトのラッパー・メソッドに戻されます。これらの新規の値はコール元に戻す必要がありますが、ラッパー・メソッド内の仮パラメータはコール元で参照できる実際のパラメータには影響を与えません。
Javaの場合、OUTまたはIN OUTの指定はありませんが、ホルダーを介して値を戻すことができます。JPublisherでは、PL/SQLのOUTまたはIN OUTパラメータを処理するホルダーのかわりに、次の代替メカニズムのいずれかを指定できます。
配列
Java API for XML-based Remote Procedure Call(JAX-RPC)ホルダー・タイプ
ファンクションの戻り
-outargumentsオプションを使用すると、どのメカニズムを使用するかを指定できます。この機能はWebサービスに特に有効です。
以降の各項では、この3つのメカニズムについて説明します。
Javaで出力値を戻すという問題を解決する場合、単一要素配列のラッパー・メソッドにOUTまたはIN OUTパラメータを渡す方法があります。配列は、パラメータを保持するコンテナとみなされます。このメカニズムは次のように動作します。
そのパラメータの前の値を配列の要素[0]に割り当てます。
配列をラッパー・メソッドへ渡します。
ラッパー・メソッドはパラメータの後の値を配列の要素[0]に割り当てます。
メソッドを実行した後に配列から後の値を抽出します。
-outarguments=arrayの設定(デフォルト)は、JPublisherに対し、この単一要素配列メカニズムを使用してOUTまたはIN OUT引数を公開するように指示します。
たとえば、次のようにします。
Person [] pa = {p};
x.f(pa);
p = pa[0];
xがJPublisherで生成されたクラスのインスタンスで、このクラスのf()メソッドはIN OUTパラメータとしてSQLのPERSONオブジェクトを使用するストアド・プロシージャのラッパー・メソッドであるとします。PERSON型はPerson Javaクラスにマップされ、pはPersonのインスタンスで、paは単一要素のPerson配列です。
OUTまたはIN OUTパラメータを渡すためのこのメカニズムでは、パラメータごとにユーザー・プログラムのコードに何行か追加する必要があります。たとえば、次のSQL*Plusコマンドにより作成されたPL/SQLファンクションの例を考えてみます。
SQL> CREATE OR REPLACE FUNCTION g (
a0 NUMBER,
a1 OUT NUMBER,
a2 IN OUT NUMBER,
a3 CLOB,
a4 OUT CLOB,
a5 IN OUT CLOB)
RETURN CLOB IS
BEGIN
RETURN NULL;
END;
-outarguments=arrayに設定すると、このPL/SQLファンクションは次のように公開されます。
public oracle.sql.CLOB g (
java.math.BigDecimal a0,
java.math.BigDecimal a1[],
java.math.BigDecimal a2[],
oracle.sql.CLOB a3,
oracle.sql.CLOB a4[],
oracle.sql.CLOB a5[])
インスタンスのメソッドのthisオブジェクトに変更があると、前述のような問題が発生します。
thisオブジェクトは異なる方法で渡される追加パラメータです。CREATE TYPE文で宣言されるそのモードはINまたはIN OUTになります。thisオブジェクトのモードを明示的に宣言しない場合のモードは、ストアド・プロシージャが結果を戻さない場合にはIN OUT、結果を戻す場合はINになります。
thisオブジェクトのモードがIN OUTの場合、ラッパー・メソッドはthisの新規の値を戻す必要があります。JPublisherで生成されたコードでは、次のように状況に応じてこの機能が異なる方法で実装されます。
結果を戻さないストアド・プロシージャの場合、thisの新規の値がラッパー・メソッドの結果として戻されます。
たとえば、SQLオブジェクト型MYTYPEに次のメンバー・プロシージャがあるとします。
MEMBER PROCEDURE f1(y IN OUT INTEGER);
また、JPublisherで対応するJavaクラスMyJavaTypeが生成されるとします。このクラスでは、次のメソッドが定義されます。
MyJavaType f1(int[] y)
f1()メソッドは、変更後のthisオブジェクトの値をMyJavaTypeインスタンスとして戻します。
ストアド・ファンクション(結果を戻すストアド・プロシージャ)の場合、ラッパー・メソッドは結果としてストアド・ファンクションの結果を戻します。thisの新規の値は単一要素の配列で戻され、ラッパー・メソッドに追加の引数(最後の引数)として渡されます。
SQLオブジェクト型MYTYPEに次のメンバー関数があるとします。
MEMBER FUNCTION f2(x IN INTEGER) RETURNS VARCHAR2;
対応するJavaクラスMyJavaTypeで次のメソッドが定義されます。
String f2(int x, MyJavaType[] newValue)
f2()メソッドはVARCHAR2値をJava文字列として戻し、変更後のthisオブジェクトの値をMyJavaType配列の配列要素として戻します。
|
注意: PL/SQLの静的プロシージャまたはファンクションの場合、JPublisherではラッパー・クラスに静的メソッドではなくインスタンスのメソッドが生成されます。これは、データベース接続を各ラッパー・クラスのインスタンスに対応付けるための方法です。接続インスタンスはラッパー・クラスのインスタンスの初期化に使用されるため、ラッパー・メソッドをコールするときに、接続または接続コンテキスト・インスタンスを明示的に提供する必要はありません。 |
JAX-RPC仕様では、単純なXMLデータ型とその他の型のJavaマッピングについて、javax.xml.rpc.holdersパッケージ内でホルダー・クラスが明示的に指定されています。通常、ホルダー・クラス名の場合は、型名にHolderが追加されます。たとえば、BigDecimalHolderはBigDecimalのホルダー・クラスです。
-outarguments=holderに設定すると、JPublisherではホルダー・インスタンスを使用してストアド・プロシージャからのOUTおよびIN OUT引数が公開されます。ホルダー設定は、JPublisherスタイル・ファイル内で指定します。設定は、該当するマッピングのTARGETTYPEセクションのHOLDERサブタグ内で指定します。ホルダー・クラスを指定しない場合、JPublisherではデフォルトに従って選択されます。
JAX-RPCおよびホルダーの概要は、次のURLで入手可能なJava API for XML-based RPC (JAX-RPC) 1.0仕様を参照してください。
http://jcp.org/aboutJava/communityprocess/final/jsr101/index.html
たとえば、次のSQL*Plusコマンドにより作成されたPL/SQLファンクションの例を考えてみます。
SQL> CREATE OR REPLACE FUNCTION g (
a0 NUMBER,
a1 OUT NUMBER,
a2 IN OUT NUMBER,
a3 CLOB,
a4 OUT CLOB,
a5 IN OUT CLOB)
RETURN CLOB IS
BEGIN
RETURN NULL;
END;
webservices10スタイル・ファイルに-outarguments=holderのエントリが含まれ、g()ファンクションを公開する次のJPublisherコマンドを使用するとします。
% jpub -u scott -s toplevel"(g)":ToplevelG -style=webservices10
Enter scott password: password
公開されるインタフェースを次に示します。
public java.lang.String g
(java.math.BigDecimal a0,
javax.xml.rpc.holders.BigDecimalHolder _xa1_out_x,
javax.xml.rpc.holders.BigDecimalHolder _xa2_inout_x,
java.lang.String a3,
javax.xml.rpc.holders.StringHolder _xa4_out_x,
javax.xml.rpc.holders.StringHolder _xa5_inout_x)
throws java.rmi.RemoteException;
この場合は、追加の抽象レベルが存在します。oracle.sql.CLOBはWebサービスでサポートされないため、StringHolderのJAX-RPCホルダー・クラスであるStringにマップされます。
JAX-RPCホルダー型または配列を使用しないWebサービスでは、メソッドのシグネチャのサポートに対する回避策として-outarguments=return設定を使用できます。JAX-RPCホルダーのサポートがない場合は、-outarguments=return設定を使用するとOUT または IN OUTデータをファンクションの結果で戻すことができます。
次のSQL*Plusコマンドにより作成されたPL/SQLファンクションの例を考えてみます。
SQL> CREATE OR REPLACE FUNCTION g (
a0 NUMBER,
a1 OUT NUMBER,
a2 IN OUT NUMBER,
a3 CLOB,
a4 OUT CLOB,
a5 IN OUT CLOB)
RETURN CLOB IS
BEGIN
RETURN NULL;
END;
g()ファンクションを公開する次のJPublisherコマンドを考えてみます。webservices10スタイル・ファイルには-outarguments=holderが指定されていますが、-style設定の後に-outarguments=return設定があるため、この設定が優先されます。
% jpub -u scott -s toplevel"(g)":ToplevelG -style=webservices10 -outarguments=return
Enter scott password: password
JPublisherの出力は次のようになります。
SCOTT.top_level_scope
ToplevelGUser_g_Out
JPublisherの出力を調べると、SCOTTのトップレベルが処理されることがわかります。また、戻りデータを介してg()ファンクションの出力値をサポートするためにToplevelGUser_g_Out Javaクラスが作成されることを示しています。
|
注意:
|
JPublisherでは、入力パラメータを取って出力パラメータを戻す次のインタフェースが生成されます。
public ToplevelGUser_g_Out g
(java.math.BigDecimal a0,
java.math.BigDecimal xxa2_inoutxx,
java.lang.String a3,
java.lang.String xxa5_inoutxx)
throws java.rmi.RemoteException;
TopLevelGUser_g_Outクラスは次のように生成されます。
public class ToplevelGUser_g_Out{
public ToplevelGUser_g_Out() { }
public java.math.BigDecimal getA1Out() { return a1_out; }
public void setA1Out(java.math.BigDecimal a1_out) { this.a1_out = a1_out; }
public java.math.BigDecimal getA2Inout() { return a2_inout; }
public void setA2Inout(java.math.BigDecimal a2_inout)
{ this.a2_inout = a2_inout; }
public java.lang.String getA4Out() { return a4_out; }}
ToplevelGUser_g_Out戻り型には、ファンクションのコール元に渡されるOUTおよびIN OUTパラメータの値がカプセル化されます。前の項のように、oracle.sql.CLOBはwebservices10スタイル・ファイルによりStringにマップされます。
PL/SQLでは、Javaと同様に、オーバーロードされたメソッド、つまり同じ名前でシグネチャが異なる2つ以上のメソッドを作成できます。ただし、PL/SQLで異なるシグネチャを持つ複数のオーバーロードされたメソッドが、Java(特にユーザー・サブクラス)で同じシグネチャを持つ場合があります。たとえば、次のPL/SQLストアド・プロシージャを考えてみます。
PROCEDURE foo(x CLOB); PROCEDURE foo(x NCHAR);
JPublisherで-style=webservices-common設定を使用してこれらのストアド・プロシージャを処理すると、Javaではすべてが同じシグネチャを持つことになります。
void foo(String x); void foo(String x);
JPublisherは、戻り型の1文目と各引数の型(該当する場合)の1文字目をメソッド名に追加し、この種の名前の競合を解決します。それでも競合が残る場合は、番号も追加されます。前述の競合は次のように解決されます。
void foo(String x); void fooS(String x);
PL/SQLでは、同じファミリの型のオーバーロードが許可されないことに注意してください。たとえば、次の例は無効です。
PROCEDURE foo(x DECIMAL); PROCEDURE foo(x INT); PROCEDURE foo(x INTEGER);
かわりに、プロシージャを同じファミリからの戻り型を使用するファンクションとみなします。次の例は、引数の型が異なるため有効です。
FUNCTION foo(x FLOAT) RETURN DECIMAL; FUNCTION foo(x VARCHAR2) RETURN INT; FUNCTION foo(x Student_T) RETURN INTEGER;
デフォルトでは、これらはJavaメソッドに次のようにマップされます。
java.math.BigDecimal foo(Float x); java.math.BigDecimal foo(String x); java.math.BigDecimal foo(StudentT x);
JPublisherでは、シグネチャが異なるため、すべての名前にfoo()を使用できます。ただし、すべてのメソッド名を一意にする必要がある場合(Webサービスでは必須)、JPublisherの-methodsオプションにunique設定を使用します。-methods=に設定すると、各メソッドは前述のネーミング・メカニズムを使用して次のように公開されます。
java.math.BigDecimal foo(Float x); java.math.BigDecimal fooBS(String x); java.math.BigDecimal fooBS1(StudentT x);
-methods=all(デフォルト)または-methods=true設定の場合、通常、JPublisherはORADataおよびSQLData実装を使用して、PL/SQLパッケージ用とオブジェクト型用のSQLJクラスを生成します。ただし、オブジェクト型にメソッドが定義されていない場合、SQLJクラスは生成されず、生成されるJavaクラスはSQLJランタイムを必要としません。
SQLJクラスには、オブジェクト型およびパッケージのサーバー・メソッド(ストアド・プロシージャ)をコールするラッパー・メソッドが含まれます。この項では、この種のクラスの使用方法について説明します。
この項の内容は、次のとおりです。
JPublisherで生成されるSQLJクラスについての注意事項は、次のとおりです。
SQL型階層のJavaラッパー・クラスを生成する場合にいずれかの型にストアド・プロシージャが含まれていると、デフォルトでは、ストアド・プロシージャを含む型のみではなく、すべてのSQL型のSQLJクラスが生成されます。
|
注意: JPublisherの-methods=false設定を使用すると、SQLJクラスの生成を明示的に抑制できます。この場合は、すべてが非SQLJクラスとなります。 |
JPublisherに用意されているクラスには、release()メソッドが含まれています。JPublisherで生成されたラッパー・クラスのインスタンスが暗黙的にDefaultContextインスタンスを構成する場合は、release()メソッドを使用して、不要になった時点でこの接続コンテキスト・インスタンスを解放する必要があります。ただし、この使用例は、ラッパー・クラスのインスタンスを作成して使用する際に次の提案の1つ以上に従うことで回避できます。
明示的に提供するSQLJ接続コンテキストを使用してラッパー・クラスのインスタンスを構成します。
setConnectionContext()メソッドを介して、ラッパー・クラスのインスタンスをSQLJ接続コンテキスト・インスタンスに明示的に対応付けます。
ラッパー・クラスのインスタンスに静的なSQLJのデフォルト接続コンテキスト・インスタンスを暗黙的に使用します。これは、接続情報を指定しない場合に発生します。
Oracle8i互換モードでは、DefaultContextインスタンスまたはユーザー指定クラスのインスタンスを取るコンストラクタのかわりに、単にConnectionContextインスタンスを取るコンストラクタがあります。これは、DefaultContextクラスなど、標準sqlj.runtime.ConnectionContextインタフェースを実装するどのクラスのインスタンスでもかまいません。
JPublisherでPL/SQLパッケージ用に生成されるクラスを使用する場合は、次の手順を実行します。
クラスのインスタンスを構成します。
クラスのラッパー・メソッドをコールします。
クラスのコンストラクタは、データベース接続をクラスのインスタンスに対応付けます。SQLJ DefaultContextインスタンス、またはJPublisherの実行時に-contextオプションで指定したクラスのインスタンスを取るコンストラクタがあります。JDBC Connectionインスタンスを取るコンストラクタもあります。また、引数を取らないコンストラクタもあります。引数のないコンストラクタをコールするのは、DefaultContextインスタンスを取るコンストラクタにSQLJのデフォルト・コンテキストを渡すのと同じです。JPublisherには、接続コンテキストやデフォルト・コンテキストなどのSQLJ概念をよく理解していないJDBCプログラマが使用しやすいように、Connectionインスタンスを使用するコンストラクタが用意されています。
thisオブジェクトの接続コンテキストがラッパー・メソッドで使用されているため、ラッパー・メソッドはすべてインスタンス・メソッドになります。
PL/SQLパッケージ用に生成されたクラスには、接続コンテキスト以外のインスタンス・データがないため、通常は使用する接続コンテキストごとにクラス・インスタンスを1つ構成します。デフォルトのコンテキストが唯一の使用するコンテキストである場合は、引数のないコンストラクタを1度コールできます。
PL/SQLパッケージ用に生成されたクラスのインスタンスには、PL/SQLパッケージ変数のコピーは含まれていません。それはORADataクラスでもSQLDataクラスでもなく、ホスト変数としても使用できません。
JPublisherでSQLオブジェクト型またはSQL OPAQUE型用に生成されたJavaクラスのインスタンスを使用するには、最初にJavaオブジェクトを初期化する必要があります。そのためには、次の方法があります。
Javaオブジェクトに対して初期化済のJavaオブジェクトを割り当てます。
SQLオブジェクトのコピーを次の方法でJavaオブジェクトに取り込みます。SQLオブジェクトをJPublisherで生成されたラッパー・メソッドのOUT引数またはファンクション・コールの戻り値として使用する方法があります。また、ユーザー記述のJDBCコールを介してSQLオブジェクトを取り出す方法もあります。下位互換性モードでSQLJソース・ファイルを直接使用する場合は、SQLJの#sql文を介してSQLオブジェクトのコピーを取り出すことができます。
引数のないコンストラクタでJavaオブジェクトを構成し、setXXX()メソッドを使用してその属性を設定するか、すべてのオブジェクト属性の値を受け入れるコンストラクタでJavaオブジェクトを構成します。その後、setConnection()またはsetConnectionContext()メソッドを使用して、ラッパー・メソッドをコールする前にオブジェクトをデータベース接続に関連付ける必要があります。オブジェクトをJDBCまたはSQLJ接続に明示的に関連付けずに、そのメソッドをコールすると、メソッドはSQLJのデフォルト・コンテキストに暗黙的に関連付けられます。
クラスの他のコンストラクタは接続をクラス・インスタンスに関連付けます。DefaultContextインスタンス、またはJPublisherの実行時に-contextオプションを通じて指定したクラスのインスタンスを取るコンストラクタと、Connectionインスタンスを取るコンストラクタがあります。接続コンテキストやデフォルト・コンテキストなどのSQLJ概念をよく理解していないJDBCプログラマが使用しやすいように、Connectionインスタンスを使用するコンストラクタが用意されています。
Javaオブジェクトを初期化すると、次を実行できます。
オブジェクトのアクセッサ・メソッドをコールできます。
オブジェクトのラッパー・メソッドをコールできます。
オブジェクトを他のラッパー・メソッドに渡すことができます。
オブジェクトをJDBCコールのホスト変数として使用できます。下位互換性モードでSQLJソース・ファイルを直接使用する場合は、SQLJの#sql文でオブジェクトをホスト変数として使用できます。
対応するSQLオブジェクト型の属性ごとにJava属性があり、属性ごとにgetXXX()およびsetXXX()アクセッサ・メソッドがあります。JPublisherでは属性に対してフィールドは生成されません。たとえば、fooと呼ばれる属性の場合、fooと呼ばれる対応するJava属性と、アクセッサ・メソッドgetFoo()およびsetFoo()があります。
クラスにはデフォルトで、サーバーに存在し実行される関連付けられたOracleオブジェクト・メソッドをコールするラッパー・メソッドが含まれます。サーバー・メソッドの種類に関係なく、ラッパー・メソッドはすべてインスタンス・メソッドです。thisオブジェクト内のDefaultContextは、ラッパー・メソッドで使用されます。
Oracleマッピングを使用すると、JPublisherではOracle JDBCドライバ用に次のメソッドが生成されます。
create()
toDatum()
この種のメソッドは、ORADataおよびORADataFactoryインタフェースで指定され、通常は直接使用することを意図していません。また、JPublisherでは、メソッドsetFrom(otherObject)、setValueFrom(otherObject)およびsetContextFrom(otherObject)が生成されます。これらのメソッドを使用すると、オブジェクト・インスタンス間で値や接続情報をコピーできます。
JPublisherでSQLJ接続コンテキスト・インスタンスの作成に使用されるクラスは、JPublisherの実行時に-contextオプションに設定する値に応じて異なります。次のクラスを使用できます。
-context=DefaultContext(デフォルト設定)に設定すると、JPublisherでは標準sqlj.runtime.ref.DefaultContextクラスのインスタンスが使用されます。
ユーザー定義のクラス(つまり、CLASSPATHに指定され、標準sqlj.runtime.ConnectionContextインタフェースを実装するクラス)に設定すると、JPublisherではそのクラスのインスタンスが使用されます。
-context=generatedに設定すると、JPublisherで生成されたクラスで静的Ctx接続コンテキスト・クラスが宣言されます。JPublisherでは、このクラスのインスタンスが接続コンテキスト・インスタンスに使用されます。この方法はOracle8i互換モードの場合には適切ですが、通常はお薦めしません。
|
注意: Oracle8i Databaseとは異なり、JPublisherで_ctx接続コンテキスト・インスタンスを宣言するためのルーチンはなくなりました。ただし、このルーチンは、Oracle8i互換モードで、_ctxが静的_Ctx接続コンテキスト・クラスのprotectedインスタンスとして宣言されている場合に使用されます。
|
JPublisherで生成されたラッパー・クラスのインスタンス内で、SQLJ接続コンテキスト・インスタンスまたはJDBC接続インスタンスを使用する場合は、次のことを考慮してください。
JPublisherで生成されたラッパー・クラスには、SQLJ接続コンテキスト・インスタンスを明示的に指定できるように、setConnectionContext()メソッドが用意されています。このメソッドの定義は次のとおりです。
void setConnectionContext(conn_ctxt_instance);
これにより、SQLJ接続コンテキストとして渡された接続コンテキスト・インスタンスが、ラッパー・クラス・インスタンスにインストールされます。この接続コンテキスト・インスタンスは、JPublisherの接続コンテキスト(通常はDefaultContext)に対して-context設定を通じて指定したクラスのインスタンスである必要があります。
基礎となるJDBC接続には、データベース・オブジェクトを最初に実体化するために使用される接続との互換性が必要であることに注意してください。特に、一部のオブジェクトは、オブジェクト参照型やBLOBなど、特定の接続にのみ有効な属性を持つ場合があります。
コンストラクタを通じて接続コンテキスト・インスタンスをすでに指定している場合には、setConnectionContext()メソッドを使用して再設定する必要はありません。
|
注意: setConnectionContext()メソッドを使用して接続コンテキスト・インスタンスを明示的に設定すると、接続コンテキストが正常にクローズされないという問題を回避できます。この問題が発生するのは、暗黙的に作成された接続コンテキスト・インスタンスの場合のみです。 |
該当する場合は、ラッパー・クラス・インスタンスの次のいずれかのメソッドを使用して、接続または接続コンテキスト・インスタンスを取得します。
getConnectionContext()メソッドは、JPublisherの-context設定で指定された接続コンテキスト・クラス(通常はDefaultContext)のインスタンスを戻します。
戻される接続コンテキスト・インスタンスは、明示的に設定されたインスタンス、またはJPublisherにより暗黙的に作成されたインスタンスです。
|
注意: これらのメソッドは、生成されたSQLJクラス内でのみ使用できます。必要な場合は、確実にSQLJクラスが生成されるように-methods=alwaysに設定できます。 |
JPublisherで生成されたSQLJクラス用に接続コンテキスト・インスタンスを明示的に設定していない場合は、getConnectionContext()メソッドのコール時にJDBC接続インスタンスから暗黙的に作成されます。
この場合は、処理の終了時にrelease()メソッドを使用して、SQLJランタイム内のリソースを解放する必要があります。これにより、メモリー・リンクが発生する可能性がなくなります。
JPublisherには、生成されるSQLJクラスに次のユーティリティ・メソッドが用意されています。
setFrom(anotherObject)
このメソッドは、接続および接続コンテキスト情報など、同じベース型の別のオブジェクトからコールするオブジェクトを初期化します。コール側のオブジェクトで暗黙的に作成された既存の接続コンテキスト・オブジェクトが解放されます。
setValueFrom(anotherObject)
このメソッドは、同じベース型の別のオブジェクトからコールするオブジェクトの基礎となるフィールド値を初期化します。このメソッドは、接続または接続コンテキスト情報を転送しません。
setContextFrom(anotherObject)
このメソッドは、同じベース型の別のオブジェクトの接続設定からコールするオブジェクトの、接続および接続コンテキスト情報を初期化します。コール側のオブジェクトで暗黙的に作成された既存の接続コンテキスト・オブジェクトが解放されます。このメソッドは、オブジェクト値に関連する情報を転送しません。
setFrom()メソッドとsetValueFrom()メソッドおよびsetContextFrom()メソッドの組合せのセマンティックは同じです。
-methods=false設定の場合、またはSQLオブジェクト型でメソッドが定義されていない場合、JPublisherではオブジェクト型のラッパー・メソッドは生成されません。この場合、生成されたクラスは実行時にSQLJランタイムを必要としません。したがって、JPublisherでは非SQLJクラス、つまりSQLJランタイムApplication Programming Interface(API)をコールしないクラスが生成されます。これは、ORAData実装とSQLData実装のどちらを使用する場合も同じです。
|
注意:
|
-methods=false設定のときのオブジェクト型用や、参照型、VARRAY型またはネストした表型用にJPublisherで生成されるクラスのインスタンスを使用するには、最初にオブジェクトを初期化する必要があります。
オブジェクトを初期化するには、次の方法があります。
Javaオブジェクトに対して初期化済のJavaオブジェクトを割り当てます。
SQLオブジェクトのコピーを次の方法でJavaオブジェクトに取り込みます。SQLオブジェクトを他のクラスのJPublisherで生成されたラッパー・メソッドを介してアクセスするOUT引数またはファンクション・コールの戻り値として使用する方法があります。また、ユーザー記述のJDBCコールを介してSQLオブジェクトを取り出す方法もあります。下位互換性モードでSQLJソース・ファイルを直接使用する場合は、SQLJの#sql文を介してSQLオブジェクトのコピーを取り出すことができます。
引数のないコンストラクタでJavaオブジェクトを構成して、そのデータを初期化するか、属性値に基づいてJavaオブジェクトを構成します。
SQLJクラスに生成されたコンストラクタとは異なり、非SQLJクラスに生成されたコンストラクタは接続引数を使用しません。かわりに、オブジェクトがJDBCのStatement、CallableStatementまたはPreparedStatementオブジェクトに渡されるか戻されると、JPublisherでは、Statement、CallableStatementまたはPreparedStatementオブジェクトの構成に使用する接続が適用されます。
これは、同じオブジェクトを様々な場合に様々な接続で使用できるという意味ではなく、使用できない場合もあります。オブジェクトは、特定の接続に対してのみ有効な参照またはBLOBなどのサブコンポーネントを持つ場合があります。
オブジェクトのデータを初期化するには、クラスがオブジェクト型を表す場合はsetXXX()メソッドを使用し、クラスがVARRAYまたはネストした表型を表す場合はsetArray()またはsetElement()メソッドを使用します。クラスが参照型を表す場合は、null参照の構成のみが可能です。非nullの参照は、すべてデータベースから取り込まれます。
オブジェクトを初期化すると、次を実行できます。
オブジェクトを他のクラスのラッパー・メソッドに渡すことができます。
オブジェクトをJDBCコールのホスト変数として使用できます。下位互換性モードでSQLJソース・ファイルを直接使用する場合は、SQLJの#sql文でオブジェクトを使用できます。
オブジェクトの状態を読取り/書込みを行うメソッドをコールできます。これらのメソッドはユーザーのプログラム内のJavaオブジェクトで動作し、データベース内のデータには影響しません。オブジェクトの状態の読取り/書込みを行うには、次の方法があります。
オブジェクト型を表すクラスの場合は、getXXX()およびsetXXX()アクセッサ・メソッドをコールします。
VARRAYまたはネストした表を表すクラスの場合は、getArray()、setArray()、getElement()およびsetElement()メソッドをコールします。
getArray()およびsetArray()メソッドは配列を全体として戻すか、あるいは変更します。getElement()およびsetElement()メソッドは配列の個別の要素を戻すか、あるいは変更します。
データベースでデータを更新する場合は、Java配列をデータベースに再挿入する必要があります。
オブジェクト参照は不変なエンティティであるため変更できません。ただし、getValue()およびsetValue()メソッドを使用して、参照するSQLオブジェクトの読取り/書込みができます。
getValue()メソッドは、オブジェクト参照で参照されているSQLオブジェクトのコピーを戻します。setValue()メソッドは、オブジェクト型を入力として表すJavaクラスのインスタンスを使用して、データベース内のSQLオブジェクト型インスタンスを更新します。オブジェクト型用に生成されたクラスのgetXXX()およびsetXXX()アクセッサ・メソッドとは異なり、getValue()およびsetValue()メソッドでSQLオブジェクトの読取り/書込みを行います。
getValue()およびsetValue()メソッドでは、それぞれ参照先である基礎となるデータベース・オブジェクトの値の読取りと書込みのために、データベースとのラウンドトリップが発生することに注意してください。
JDBCコードでgetORADataFactory()メソッドを使用すると、ORADataFactoryオブジェクトを戻すことができます。このORADataFactoryオブジェクトを、oracle.jdbcパッケージのArrayDataResultSet、OracleCallableStatementおよびOracleResultSetクラス内でgetORAData()メソッドに渡すことができます。Oracle JDBCドライバでは、ORADataFactoryオブジェクトを使用して、JPublisherで生成されたクラスのインスタンスが作成されます。
さらに、VARRAYおよびネストした表型を表すクラスには、oracle.sql.ARRAYクラスの機能を実装するメソッドがあります。これらのメソッドを次に示します。
getBaseTypeName()
getBaseType()
getDescriptor()
ただし、VARRAYおよびネストした表型用にJPublisherで生成されたクラスはoracle.sql.ARRAYクラスを拡張しません。
Oracleマッピングを使用すると、JPublisherではOracle JDBCドライバ用に次のメソッドが生成されます。
create()
toDatum()
この種のメソッドは、ORADataおよびORADataFactoryインタフェースで指定され、通常は直接使用することを意図していません。ただし、2つのオブジェクト参照Javaラッパー型の間で変換する場合には使用できます。
JPublisherには、クラス生成機能のみでなくインタフェース生成機能も用意されています。この機能は、WSDLコンテンツの生成に使用するAPIを表すJavaインタフェースを手動で作成する必要がなくなるため、特にWebサービスに有効です。
-sqlオプションでは次の構文がサポートされます。
-sql=sql_package_or_type:JavaClass#JavaInterface
または
-sql=sql_package_or_type:JavaClass:JavaUserSubclass#JavaSubInterface
クラスとともにインタフェース名を指定すると、そのクラスのパブリック属性またはラッパー・メソッド(あるいはその両方)がインタフェースで提供され、生成されるクラスにそのインタフェースが実装されます。
インタフェースは、生成されるクラスまたはユーザー・サブクラスの両方ではなく、どちらか一方についてのみ指定します。生成されるベース・クラス用のインタフェースとユーザー・サブクラス用インタフェースとの違いには、Java間の型変換が関係します。サブクラスのメソッドのシグネチャは、Java間のマッピングの関係でベース・クラスでのシグネチャとは異なる場合があります。
ユーザー定義のSQL型の変換時に、JPublisherにより生成されたカスタムJavaクラスの機能を拡張できます。
その方法の1つは、JPublisherで生成されたクラスにメソッドを手動で追加することです。ただし、将来JPublisherを実行してクラスを再生成することになると思われる場合、この方法は望ましくありません。この方法で変更されたクラスを再生成すると、変更内容(追加したメソッドなど)が上書きされます。JPublisher出力を別のファイルに送る場合にも、変更内容をそのファイルにマージする必要があります。
生成されたクラスの機能を拡張する場合に望ましい方法は、クラスの拡張です。JPublisherにはクラス拡張メカニズムが用意されており、必要に応じてカスタマイズできるように元のベース・クラスがスタブ・サブクラスとともに生成されます。コードでSQL型が参照されるたびに(引数として使用される場合など)、そのSQL型がベース・クラスではなくサブクラスにマップされます。
JPublisherで生成されるサブクラスには、Java間の型変換に関する使用例もあります。SQL型からJava型へのマッピングには、Webサービスでサポートされていない型など、目的に適さないJava型が使用される場合があります。JPublisherでは、スタイルおよびスタイル・ファイルのメカニズムを使用して、適切なJava型を使用するためのJava変換間ステップを追加できます。
各項の内容は、次のとおりです。
JPublisherでADDRESS SQLオブジェクト型からJAddressクラスを生成するとします。また、MyAddressクラスを記述してADDRESSオブジェクトを表すと想定します。このMyAddressはJAddressが提供する機能を拡張します。
この使用例では、JPublisherを使用してベースJavaクラスJAddressとサブクラスMyAddressの初期バージョンを生成し、この初期バージョンに必要な機能を追加できます。次にJPublisherを使用してADDRESSオブジェクトをJAddressクラスのかわりにMyAddressクラスにマップします。
これを実行するために、JPublisherで生成されるコードが次の方法で変更されます。
JAddressRefではなくMyAddressRef参照クラスを生成します。
SQL型がADDRESSの属性を表すため、あるいはSQL型がADDRESSのVARRAYおよびネストした表の要素を表すために、JAddressクラスではなくMyAddressクラスを使用します。
ORADataFactoryインタフェースを使用してSQL型がADDRESSであるJavaオブジェクトを構成する場合に、JAddressファクトリではなくMyAddressファクトリを使用します。
JAddressクラス用のコードを生成または再生成します。また、MyAddressクラス用のコードの初期バージョンも生成されます。これを変更して、独自の追加機能を挿入できます。ただし、MyAddressクラスのソース・ファイルがすでに存在している場合は、JPublisherによってそれがそのまま残ります。
JPublisherは代替クラスに対するマッピング処理を効率化する機能を備えています。-sqlコマンドライン・オプション設定で次の構文を使用します。
-sql=object_type:generated_base_class:map_class
MyAddress/JAddressの例の場合は、次のようになります。
-sql=ADDRESS:JAddress:MyAddress
コマンドラインではなくINPUTファイルに行を入力すると、次のようになります。
SQL ADDRESS GENERATE JAddress AS MyAddress
この構文で、JAddressはJPublisherでJAddress.javaに生成されるベース・クラスの名前を示しますが、MyAddressは実際にADDRESSにマップするクラスの名前です。最終的には、MyAddress.java内のコードを取り扱う必要があります。カスタム機能を追加するには、このコードを必要に応じて更新します。ADDRESS属性を持つオブジェクトを取り出すと、この属性はMyAddressのインスタンスとして作成されます。あるいはADDRESSオブジェクトを直接取り出すと、MyAddressのインスタンスに取り込まれます。
ユーザー・サブクラスの初期バージョンが存在しない場合は、JPublisherにより自動的に生成されます。このサブクラスに、カスタム・コードを挿入します。たとえば、前述の例ではJPublisherによってMyAddress.javaファイルに生成されています。
次の点に注意してください。
クラスには引数のないコンストラクタがあります。適切な初期化オブジェクトを構成する場合は、スーパークラスのコンストラクタを明示的または暗黙的にコールするのが最も簡単な方法です。
クラスはORADataインタフェースまたはSQLDataインタフェースを実装します。この実装は、スーパークラスから必要なメソッドを継承することで暗黙的に行われます。
ORADataクラスを拡張すると、サブクラスもORADataFactoryインタフェースを実装します。create()メソッドの実装は、次のようになります。
public ORAData create(Datum d, int sqlType) throws SQLException
{
return create(new UserClass(),d,sqlType);
}
ただし、クラスが継承階層に含まれている場合、生成されたメソッドはcreate()と同じシグネチャおよび本体を持つprotected ORAData createExact()に変わります。
この項では、ORAData型の継承のサポートについて説明します。この項の内容は、次のとおりです。
JPublisherでの継承サポートの実装方法。
サブタイプの参照クラスではベース型の参照クラスが拡張されない理由、およびある参照型から別の参照型(通常はサブクラスまたはスーパークラス)への変換方法。
この項の内容は、次のとおりです。
次のSQLオブジェクト型について考えます。
CREATE TYPE PERSON AS OBJECT ( ... ) NOT FINAL; CREATE TYPE STUDENT UNDER PERSON ( ... ); CREATE TYPE INSTRUCTOR UNDER PERSON ( ... );
対応するJavaクラスを作成する次のJPublisherコマンドについて考えます。
% jpub -user=scott -sql=PERSON:Person,STUDENT:Student,INSTRUCTOR:Instructor -usertypes=oracle
Enter scott password: password
この例では、JPublisherによりPersonクラス、StudentクラスおよびInstructorクラスが生成されます。STUDENTとINSTRUCTORはPERSONのサブタイプであるため、StudentクラスとInstructorクラスはPersonクラスを拡張します。
継承階層のルートにあるクラス(この例ではPerson)には、継承階層全体のすべての情報が含まれ、その型マップは必要な情報で自動的に初期化されます。JPublisherを使用してクラス階層に必要なクラスをすべて生成すると、追加のアクションは不要です。そのままでクラス階層の型マップを適切に移入できます。
この項の内容は、次のとおりです。
SQL型階層に対してJPublisherを数回実行し、そのたびに対応するJavaラッパー・クラスの一部のみを生成する場合は、クラス階層のルートにある型マップが適切に初期化されるように、ユーザー・アプリケーションで事前作業を実行する必要があります。
前述の例で、次のJPublisherコマンドを実行したとします。
% jpub -user=scott -sql=PERSON:Person,STUDENT:Student -usertypes=oracle Enter scott password: password % jpub -user=scott -sql=PERSON:Person,INSTRUCTOR:Instructor -usertypes=oracle Enter scott password: password
この場合は、これらのマップされた型をコードで使用する前に、生成されたクラス(少なくともリーフ・クラス)のインスタンスを作成する必要があります。たとえば、次のようにします。
new Instructor(); // required new Student(); // required new Person(); // optional
Personクラスには次のメソッドが含まれます。
Person create(oracle.sql.Datum d, int sqlType)
このメソッドは、DatumインスタンスをカスタムJavaオブジェクトとしての表現に変換します。PERSONとして宣言されたSQLオブジェクトがPerson変数に取り出されるたびに、Oracle JDBCドライバによりコールされます。ただし、SQLオブジェクトが実際にはSTUDENTオブジェクトである場合があります。この場合、create()メソッドではPersonインスタンスではなくStudentインスタンスを作成する必要があります。
この種の状況を処理するには、カスタムJavaクラスのcreate()メソッドで、oracle.sql.Datum引数に対応するSQLオブジェクト型のサブタイプを表すサブクラスのインスタンスを作成できる必要があります。これにより、作成されたJavaオブジェクトの実際の型が、SQLオブジェクトの実際の型と一致することが保証されます。JPublisherでは、カスタムJavaクラスが作成される場合と作成されない場合があります。
ただし、カスタムJavaクラス階層のルート・クラスにあるcreate()メソッドのコードでは、サブクラスを指定する必要はありません。実際、サブクラスが指定された場合には、新規サブクラスを記述または作成するときに、ベース・クラス用のコードを変更する必要があります。JPublisherを使用してクラス階層全体を再生成するとベース・クラスが自動的に変更されます。ただし、常に階層を再生成できるとはかぎりません。たとえば、拡張するJavaクラスのソース・コードへのアクセス権がない場合などです。
かわりに、JPublisherで生成されたコードは、カスタムのJavaクラス階層の各サブクラスに静的な初期化ブロックを作成することで、クラス階層の増分拡張を行うことができます。この静的な初期化ブロックでは、ルート・クラスにはサブクラスに関して必要な情報が与えられ、ルート・レベルのJavaクラスで宣言されたデータ構造が初期化されます。サブクラスのインスタンスが実行時に作成されると、その型がデータ構造に登録されます。この暗黙的なマッピング・メカニズムのため、SQLDataの使用例とは異なり、明示的な型マップは不要です。
|
注意: この実装により既存のクラスを修正せずに拡張できますが、デメリットもあります。クラス階層を使用してデータベースからオブジェクトを読み取る前に、サブクラスの静的初期化ブロックが処理される必要があります。これが発生するのは、new()をコールして各サブクラスのオブジェクトをインスタンス化する場合です。サブクラスのコンストラクタにより、すぐ上位のスーパークラスのコンストラクタがコールされるため、リーフ・クラスのみがインスタンス化されます。
かわりに、実行可能な場合は、クラス階層全体を生成または再生成できます。 |
この項では、カスタム参照クラス間での変換方法と、JPublisherによってサブタイプ用に生成されるカスタム参照クラスが、ベース型の参照クラスを拡張しない理由について説明します。
この項の内容は、次のとおりです。
「ORADataのオブジェクト型および継承」の例では、基礎となるオブジェクト型のラッパー・クラスに加えて、強い型指定の参照用にPersonRef、StudentRefおよびInstructorRefを取得しています。
StudentRefインスタンスがあり、それをPersonRefインスタンスの必要なコンテキスト内で使用することが必要な場合があります。この場合は、強い型指定の参照クラスに生成される静的メソッドcast()を使用します。
StudentRef s_ref = ...; PersonRef p_ref = PersonRef.cast(s_ref);
逆に、PersonRefインスタンスがあり、それをInstructorRefインスタンスへと限定できることがわかっている場合があります。
PersonRef pr = ...; InstructorRef ir = InstructorRef.cast(pr);
ここでは、参照型を関連オブジェクト型の階層に従わせることが望ましくない理由を、例をあげて説明します。わかりやすいように、前項と同じ例のサブセットについて考えます。
CREATE TYPE PERSON AS OBJECT ( ... ) NOT FINAL; CREATE TYPE STUDENT UNDER PERSON ( ... );
さらに次のJPublisherコマンドを考えてみます。
% jpub -user=scott -sql=PERSON:Person,STUDENT:Student -usertypes=oracle
Enter scott password: password
Java型PersonおよびStudentが生成され、さらにPersonRef型とStudentRef型も生成されます。
StudentクラスはPersonクラスを拡張するため、StudentRefでPersonRefが拡張されると予期できます。ただし、StudentRefクラスは独立クラスとしてPersonRefのサブタイプより強いコンパイル時の型保証を提供できるため、これには該当しません。また、PersonRefオブジェクトではデータベース内のPersonオブジェクトの変更などが可能ですが、これはStudentRefオブジェクトではできません。
PersonRefクラスの最も重要なメソッドは次のとおりです。
Person getValue()
void setValue(Person c)
StudentRefクラスで対応するメソッドは次のとおりです。
Student getValue()
void setValue(Student c)
StudentRefクラスがPersonRefクラスを拡張すると、次の問題が発生します。
Javaでは、PersonRefクラス内でオーバーライドするメソッドがPersonオブジェクトを戻す場合、StudentRefのgetValue()メソッドがStudentオブジェクトを戻すことは、たとえ適切であっても許可されません。
StudentRefのsetValue()メソッドはPersonRefのsetValue()メソッドをオーバーライドしません。これは、この2つのメソッドのシグネチャが異なるためです。
StudentRefメソッドにPersonRefメソッドと同じシグネチャおよび結果の型を指定しても、この問題は修正できません。これは、オブジェクトをPersonRefではなくStudentRefとして宣言することで得られる追加の型保証が失われるためです。
参照型は関連オブジェクト型の階層に従わないため、2つの参照型の間では直接変換することはできません。これはJPublisherの制限です。背景情報として、この項では生成されたcast()メソッドによる参照型間の変換操作について説明します。
|
注意: これらの手動手順に従うことはお薦めしません。ここではあくまでも参考のために説明しています。かわりに、cast()メソッドを使用できます。 |
次の例に、XxxxRef参照型からYyyyRef参照型への変換に使用できるコードを示します。
java.sql.Connection conn = ...; // get underlying JDBC connection
XxxxRef xref = ...;
YyyyRef yref = (YyyyRef) YyyyRef.getORADataFactory().
create(xref.toDatum(conn),oracle.jdbc.OracleTypes.REF);
この変換は2つのステップで構成され、各ステップに独自のメリットがあります。
xrefを強いXxxxRef型から弱いoracle.sql.REF型に変換します。
oracle.sql.REF ref = (oracle.sql.REF) xref.toDatum(conn);
oracle.sql.REF型からターゲットのYyyyRef型に変換します。
YyyyRef yref = (YyyyRef) YyyyRef.getORADataFactory().
create(ref,oracle.jdbc.OracleTypes.REF);
|
注意: この変換では、タイプ・チェックは行われません。この変換が実際に許可されるかどうかは、使用中のアプリケーションおよびSQLスキーマに応じて異なります。 |
次の例にはSQL定義とJavaコードが含まれており、前述のポイントを示しています。
SQL定義 次のSQL定義について考えます。
CREATE TYPE person_t AS OBJECT (ssn NUMBER, name VARCHAR2(30), dob DATE) NOT FINAL;
/
SHOW ERRORS
CREATE TYPE instructor_t UNDER person_t (title VARCHAR2(20)) NOT FINAL;
/
SHOW ERRORS
CREATE TYPE instructorPartTime_t UNDER instructor_t (num_hours NUMBER);
/
SHOW ERRORS
CREATE TYPE student_t UNDER person_t (deptid NUMBER, major VARCHAR2(30)) NOT FINAL;
/
SHOW ERRORS
CREATE TYPE graduate_t UNDER student_t (advisor instructor_t);
/
SHOW ERRORS
CREATE TYPE studentPartTime_t UNDER student_t (num_hours NUMBER);
/
SHOW ERRORS
CREATE TABLE person_tab OF person_t;
INSERT INTO person_tab VALUES (1001, 'Larry', TO_DATE('11-SEP-60'));
INSERT INTO person_tab VALUES (instructor_t(1101, 'Smith', TO_DATE('09-OCT-1940'), 'Professor'));
INSERT INTO person_tab VALUES (instructorPartTime_t(1111, 'Myers', TO_DATE('10-OCT-65'), 'Adjunct Professor', 20));
INSERT INTO person_tab VALUES (student_t(1201, 'John', To_DATE('01-OCT-78'), 11, 'EE'));
INSERT INTO person_tab VALUES (graduate_t(1211, 'Lisa', TO_DATE('10-OCT-75'), 12, 'ICS',
instructor_t(1101, 'Smith', TO_DATE ('09-OCT-40'), 'Professor')));
INSERT INTO person_tab VALUES (studentPartTime_t(1221, 'Dave', TO_DATE('11-OCT-70'), 13, 'MATH', 20));
JPublisherのマッピング JPublisherの実行時に次のマッピングがあるとします。
Person_t:Person,instructor_t:Instructor,instructorPartTime_t:InstructorPartTime, graduate_t:Graduate,studentPartTime_t:StudentPartTime
SQLJクラス 参照型間の変換例のSQLJクラスを次に示します。
import java.sql.*;
import oracle.jdbc.*;
import oracle.sql.*;
public class Inheritance
{
public static void main(String[] args) throws SQLException
{
System.out.println("Connecting.");
java.sql.DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
oracle.jdbc.OracleConnection conn =
(oracle.jdbc.OracleConnection) java.sql.DriverManager.getConnection
("jdbc:oracle:oci8:@", "scott", "tiger");
// The following is only required in 9.0.1
// or if the Java class hierarchy was created piecemeal
System.out.println("Initializing type system.");
new Person();
new Instructor();
new InstructorPartTime();
new StudentT();
new StudentPartTime();
new Graduate();
PersonRef p_ref;
InstructorRef i_ref;
InstructorPartTimeRef ipt_ref;
StudentTRef s_ref;
StudentPartTimeRef spt_ref;
GraduateRef g_ref;
OraclePreparedStatement stmt =
(OraclePreparedStatement)conn.prepareStatement
("select ref(p) FROM PERSON_TAB p WHERE p.NAME=:1");
OracleResultSet rs;
System.out.println("Selecting a person.");
stmt.setString(1, "Larry");
rs = (OracleResultSet) stmt.executeQuery();
rs.next();
p_ref = (PersonRef) rs.getORAData(1, PersonRef.getORADataFactory());
rs.close();
System.out.println("Selecting an instructor.");
stmt.setString(1, "Smith");
rs = (OracleResultSet) stmt.executeQuery();
rs.next();
i_ref = (InstructorRef) rs.getORAData(1, InstructorRef.getORADataFactory());
rs.close();
System.out.println("Selecting a part time instructor.");
stmt.setString(1, "Myers");
rs = (OracleResultSet) stmt.executeQuery();
rs.next();
ipt_ref = (InstructorPartTimeRef) rs.getORAData
(1, InstructorPartTimeRef.getORADataFactory());
rs.close();
System.out.println("Selecting a student.");
stmt.setString(1, "John");
rs = (OracleResultSet) stmt.executeQuery();
rs.next();
s_ref = (StudentTRef) rs.getORAData(1, StudentTRef.getORADataFactory());
rs.close();
System.out.println("Selecting a part time student.");
stmt.setString(1, "Dave");
rs = (OracleResultSet) stmt.executeQuery();
rs.next();
spt_ref = (StudentPartTimeRef) rs.getORAData
(1, StudentPartTimeRef.getORADataFactory());
rs.close();
System.out.println("Selecting a graduate student.");
stmt.setString(1, "Lisa");
rs = (OracleResultSet) stmt.executeQuery();
rs.next();
g_ref = (GraduateRef) rs.getORAData(1, GraduateRef.getORADataFactory());
rs.close();
stmt.close();
// Assigning a part-time instructor ref to a person ref
System.out.println("Assigning a part-time instructor ref to a person ref");
oracle.sql.Datum ref = ipt_ref.toDatum(conn);
PersonRef pref = (PersonRef) PersonRef.getORADataFactory().
create(ref,OracleTypes.REF);
// or just use: PersonRef pref = PersonRef.cast(ipt_ref);
// Assigning a person ref to an instructor ref
System.out.println("Assigning a person ref to an instructor ref");
InstructorRef iref = (InstructorRef) InstructorRef.getORADataFactory().
create(pref.toDatum(conn), OracleTypes.REF);
// or just use: InstructorRef iref = InstructorRef.cast(pref);
// Assigning a graduate ref to an part time instructor ref.
// This should produce an error, demonstrating that refs
// are type safe.
System.out.println ("Assigning a graduate ref to a part time instructor ref");
InstructorPartTimeRef iptref =
(InstructorPartTimeRef) InstructorPartTimeRef.getORADataFactory().
create(g_ref.toDatum(conn), OracleTypes.REF);
// or just use: InstructorPartTimeRef iptref =
// InstructorPartTimeRef.cast(g_ref);
conn.close();
}
}
JPublisherで-usertypes=oracleのかわりに-usertypes=jdbc設定を使用すると、JPublisherで生成されるカスタムJavaクラスでは、Oracle ORADataインタフェースのかわりに標準SQLDataインタフェースが実装されます。標準SQLDataメソッドのreadSQL()およびwriteSQL()には、データの読取りと書込みに関してORAData/ORADataFactoryメソッドのcreate()およびtoDatum()と同等の機能があります。
JPublisherでは、SQL階層に対応するSQLDataクラスの生成時に、Javaの型はSQL型と同じ階層になります。これは、JPublisherでSQLオブジェクト型の階層に対応するORADataクラスが生成される場合と同じです。ただし、SQLDataの実装では、JPublisherがORADataクラスに自動的に生成する暗黙的なマッピングのインテリジェント機能がありません。
SQLDataの使用例では、SQLオブジェクト型とJavaの型の間に適切なマッピングが得られるように、型マップを手動で提供する必要があります。JDBCアプリケーションでは、接続のデフォルトの型マップを正常に初期化するか、getObject()の入力パラメータとして型マップを明示的に指定できます。
|
関連項目: 『Oracle Database JDBC開発者ガイド』 |
また、SQLData実装では、強い型指定のオブジェクト参照に対するサポートがないことに注意してください。すべてのオブジェクト参照は弱い型指定のjava.sql.Refインスタンスです。
この項では、SQL修飾子FINAL、NOT FINALまたはNOT INSTANTIABLEの使用が、JPublisherで生成されるラッパー・クラスに与える効果について説明します。
SQL修飾子FINALまたはNOT FINALをSQL型またはSQL型のメソッドに使用しても、生成されるJavaラッパー・コードには影響しません。このため、JPublisherユーザーは常に、クラスを拡張して生成された動作をオーバーライドすることで、生成されたJavaラッパー・クラスをカスタマイズできます。
NOT INSTANTIABLE SQL修飾子をSQL型のメソッドに使用すると、Javaラッパー・クラスにそのメソッド用のコードは生成されません。したがって、そのメソッドをコールするには、インスタンス化できるSQLサブタイプに対応するなんらかのラッパー・クラスにキャストする必要があります。
SQL型にNOT INSTANTIABLEを使用すると、protectedコンストラクタで対応するラッパー・クラスが生成されます。これにより、インスタンス化できるSQL型に対応するサブクラス経由でなければ、そのクラスのインスタンスを作成できないことがわかります。