- PR -

OracleへJNDI接続し、BLOB型へ挿入する際に発生するクラスキャスト例外の回避法は?

1
投稿者投稿内容
BBQ
会議室デビュー日: 2006/02/08
投稿数: 7
投稿日時: 2006-02-23 11:52
お世話になります。

以前、似たような(というより全く同じ)状況についての質問があったようですが、
結局、DriverManager接続で逃げたとのことで、これを解決する方法を
改めてお聞きしたいと思います。

状況ですが、
1)class.forNameクラスでDriverMagager.getConnection()でDB接続した場合、OK
2)DataSourceを活用して(DataSource) Context.lookup(データソース)で接続した場合、NG
となっています。

環境:
WinXP
Jdk1.4.2_10
Struts1.2.4
Tomcat5.0.28
Oracle9.2.0

JNDIに関するserver.xml記述は

<Resource name="/jdbc/develop" type="javax.sql.DataSource"/>
<ResourceParams name="/jdbc/develop">
<parameter>
<name>maxWait</name>
<value>5000</value>
</parameter>
<parameter>
<name>maxActive</name>
<value>100</value>
</parameter>
<parameter>
<name>password</name>
<value>dev_password</value>
</parameter>
<parameter>
<name>url</name>
<value>jdbc:oracle:thin:@devDB:1521:orcl</value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>oracle.jdbc.OracleDriver</value>
</parameter>
<parameter>
<name>maxIdle</name>
<value>10</value>
</parameter>
<parameter>
<name>username</name>
<value>dev_user</value>
</parameter>
</ResourceParams>

となっています。

そして、
1)DriverMagagerを使用して接続
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn=DriverManager.getConnection("jdbc:oracle:thin:@devDB:1521:orcl", "dev_user", "dev_password");
としてConnectionを取得

2)DataSourceを使用してJNDI接続
Context cx = new InitialContext();
DataSource ds = (DataSource )cx.lookup("java:comp/env/jdbc/develop");
Connection conn = ds.getConnection();
としてConnectionを取得

ここまでは、書き込みミスがあるかもしれませんが、とりあえずは実環境では
接続成功し、LOB以外のSELECT/DELETE/INSERT/UPDATEは
正常に行われているとお考えください。

問題のBLOB型の挿入箇所なのですが、
 (BLOB以外のINSERT処理)

(INSERTしたレコードをSELECT)

ResultSet rs = selStmt.executeQuery();
if (rs.next()) {
try {
BLOB blob = ((OracleResultSet) rs).getBLOB(1); // クラスキャスト例外発生箇所
OutputStream blobOutputStream = blob.getBinaryOutputStream();
blobOutputStream.write(imageData, 0, imageData.length);
blobOutputStream.close();
conn.commit();
} catch (IOException ex) {
conn.rollback();
throw new Exception(ex);
}
} else {
throw new SQLException("BLOBの格納に失敗");
}

1)の接続の場合には問題なく成功しますが、
2)の場合は、
BLOB blob = ((OracleResultSet) rs).getBLOB(1); の部分でClassCastExceptionが発生します。
これを、以下のようにしても同様に例外が発生します。
Blob _blob = rs.getBlob(1);
BLOB blob = (BLOB) _blob; // ここで例外発生

いろいろ試してみましたが、
・ResultSet → OracleResultSet へのキャスト
・java.sql.Blob → oracle.sql.BLOB へのキャスト
どちらをやっても例外が発生します。

ちなみに、
ResultSet rs = selStmt.executeQuery();
System.out.println(rs.getClass().getName());
とすると、
org.apache.commons.dbcp.DelegatingResultSet
となっています。

と、ここまでは以前の相談者の方のケースと同じです。
DriverManager接続に逃げたいところですが、その為のユーザー名、パスワードを
設定ファイル等に記述するのは、セキュリティ面からNGとされているため、
どうしてもJNDI接続の方法をとらなければなりません。
JNDI接続でBLOB挿入を実現する為の解決法、いとぐち、その他なんでも結構ですので宜しくお願いいたします。
山本 裕介
ぬし
会議室デビュー日: 2003/05/22
投稿数: 2415
お住まい・勤務地: 恵比寿
投稿日時: 2006-02-23 12:46
DBCP から受け取る ResultSet が JDBC の標準 API だけを実装したラッパオブジェクトだからでしょう。
DelegationResultSet のインターフェースを見る限り内部に保持している実際のResultSetオブジェクトを取得する方法は用意されていないようです。
商用サーバであればそういう問題もないんですが・・・
・JDBC インタフェースのベンダ拡張機能の使い方
http://www.beasys.co.jp/e-docs/wls/docs81/jdbc/thirdparty.html#1078159


DelegationResultSet.java に書き加えて ResultSet getActualResultSet() みたいなメソッドをご自分で付け加えてはいかがでしょう?
koe
大ベテラン
会議室デビュー日: 2003/07/13
投稿数: 198
投稿日時: 2006-02-23 15:46
これが使えるのではないでしょうか。
http://jakarta.apache.org/commons/dbcp/apidocs/org/apache/commons/dbcp/DelegatingResultSet.html#getInnermostDelegate()
つばさ
ベテラン
会議室デビュー日: 2005/02/05
投稿数: 54
投稿日時: 2006-02-23 21:36
以下のようなかんじで問題なくできます。

ResultSet rs = pStmt.executeQuery();
DelegatingResultSet drs = (DelegatingResultSet)rs;
OracleResultSetImpl impl = (OracleResultSetImpl)drs.getDelegate();
BLOB blob = impl.getBLOB(1);
OutputStream out = blob.getBinaryOutputStream();
int size = blob.getBufferSize();
byte[] buff = new byte[size];
BufferedInputStream bin = new BufferedInputStream(....);
int length = -1;
while ((length = bin.read(buff)) != -1) {
out.write(buff, 0, length);
}
out.close();
bin.close();
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2006-02-23 21:51
ふと疑問に思ったのですが、
BLOB blob = (BLOB)rs.getBlob();
が、なぜClassCastExceptionとなるのか疑問に思いました・・・

9.2iのclasses12.jarのOracleResultSetImplをリバースしたのですが、
getBlobメソッドはBLOBを返すgetBLOBメソッドに委譲しているだけなんですよね。

で、getBLOBメソッドで返されるBLOBのインスタンスはBlobを実装しているので、
getBlobメソッド経由ではBlob型としてしか見えませんが、
実態はBLOB型のはずなので、キャストできてもいいと思うのです。

さらに、DelegatingResultSetのgetBlobメソッドは、
独自の型でラップするわけでもなく、委譲対象の値をそのまま返しています。

何故なんでしょうか・・
今環境がないので、詳しい人は教えてください。
1

スキルアップ/キャリアアップ(JOB@IT)