この章では、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オブジェクトを構成し、set
XXX
()
メソッドを使用してその属性を設定するか、すべてのオブジェクト属性の値を受け入れるコンストラクタでJavaオブジェクトを構成します。その後、setConnection()
またはsetConnectionContext()
メソッドを使用して、ラッパー・メソッドをコールする前にオブジェクトをデータベース接続に関連付ける必要があります。オブジェクトをJDBCまたはSQLJ接続に明示的に関連付けずに、そのメソッドをコールすると、メソッドはSQLJのデフォルト・コンテキストに暗黙的に関連付けられます。
クラスの他のコンストラクタは接続をクラス・インスタンスに関連付けます。DefaultContext
インスタンス、またはJPublisherの実行時に-context
オプションを通じて指定したクラスのインスタンスを取るコンストラクタと、Connection
インスタンスを取るコンストラクタがあります。接続コンテキストやデフォルト・コンテキストなどのSQLJ概念をよく理解していないJDBCプログラマが使用しやすいように、Connection
インスタンスを使用するコンストラクタが用意されています。
Javaオブジェクトを初期化すると、次を実行できます。
オブジェクトのアクセッサ・メソッドをコールできます。
オブジェクトのラッパー・メソッドをコールできます。
オブジェクトを他のラッパー・メソッドに渡すことができます。
オブジェクトをJDBCコールのホスト変数として使用できます。下位互換性モードでSQLJソース・ファイルを直接使用する場合は、SQLJの#sql
文でオブジェクトをホスト変数として使用できます。
対応するSQLオブジェクト型の属性ごとにJava属性があり、属性ごとにget
XXX
()
およびset
XXX
()
アクセッサ・メソッドがあります。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
などのサブコンポーネントを持つ場合があります。
オブジェクトのデータを初期化するには、クラスがオブジェクト型を表す場合はset
XXX
()
メソッドを使用し、クラスがVARRAY
またはネストした表型を表す場合はsetArray()
またはsetElement()
メソッドを使用します。クラスが参照型を表す場合は、null参照の構成のみが可能です。非nullの参照は、すべてデータベースから取り込まれます。
オブジェクトを初期化すると、次を実行できます。
オブジェクトを他のクラスのラッパー・メソッドに渡すことができます。
オブジェクトをJDBCコールのホスト変数として使用できます。下位互換性モードでSQLJソース・ファイルを直接使用する場合は、SQLJの#sql
文でオブジェクトを使用できます。
オブジェクトの状態を読取り/書込みを行うメソッドをコールできます。これらのメソッドはユーザーのプログラム内のJavaオブジェクトで動作し、データベース内のデータには影響しません。オブジェクトの状態の読取り/書込みを行うには、次の方法があります。
オブジェクト型を表すクラスの場合は、get
XXX
()
およびset
XXX
()
アクセッサ・メソッドをコールします。
VARRAY
またはネストした表を表すクラスの場合は、getArray()
、setArray()
、getElement()
およびsetElement()
メソッドをコールします。
getArray()
およびsetArray()
メソッドは配列を全体として戻すか、あるいは変更します。getElement()
およびsetElement()
メソッドは配列の個別の要素を戻すか、あるいは変更します。
データベースでデータを更新する場合は、Java配列をデータベースに再挿入する必要があります。
オブジェクト参照は不変なエンティティであるため変更できません。ただし、getValue()
およびsetValue()
メソッドを使用して、参照するSQLオブジェクトの読取り/書込みができます。
getValue()
メソッドは、オブジェクト参照で参照されているSQLオブジェクトのコピーを戻します。setValue()
メソッドは、オブジェクト型を入力として表すJavaクラスのインスタンスを使用して、データベース内のSQLオブジェクト型インスタンスを更新します。オブジェクト型用に生成されたクラスのget
XXX
()
およびset
XXX
()
アクセッサ・メソッドとは異なり、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型に対応するサブクラス経由でなければ、そのクラスのインスタンスを作成できないことがわかります。