HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

幻のsun.io.MalformedInputException

SunのJava VM(j2sdk1.4.2_18、jdk1.5.0_11、jdk1.6.0_01で確認)で、以下の処理を実行させると、エラーが発生することなく終了する。(もちろん、いわゆる文字化け状態になるが‥)

byte[] b_Shift_JIS = {
    (byte) 0x8b, (byte) 0x43,  // き
    (byte) 0x82, (byte) 0xdc,  // ま
    (byte) 0x82, (byte) 0xae,  // ぐ
    (byte) 0x82, (byte) 0xea,  // れ
    (byte) 0x93, (byte) 0xfa,  // 日
    (byte) 0x8b, (byte) 0x4c,  // 記
};

System.out.println("Start");

Reader reader = new InputStreamReader(new ByteArrayInputStream(b_Shift_JIS), "UTF-8");
char[] buf = new char[128];
int len;
try {
    StringBuffer sb = new StringBuffer();
    while ((len = reader.read(buf)) > 0) {
        sb.append(buf, 0, len);
    }

    System.out.println("OK");
} catch (CharConversionException e) {
    System.out.println("CharConversionException");
    e.printStackTrace();
} catch (IOException e) {
    System.out.println("IOException");
    e.printStackTrace();
} finally {
    reader.close();
}

UTF-8としては不正なバイト列なので、例外が発生するのが自然だとも思うが、発生することはないのでまとめてIOExceptionとしてエラー処理をしていた。
ところが、Sunのj2sdk1.4.2_18、jdk1.5.0_11では、「あること」を行ってから同じ処理を実行すると、以下のように例外が発生する。

Start
CharConversionException
sun.io.MalformedInputException
    at sun.io.ByteToCharUTF8.convert(ByteToCharUTF8.java:149)
    at sun.nio.cs.StreamDecoder$ConverterSD.convertInto(StreamDecoder.java:248)
    at sun.nio.cs.StreamDecoder$ConverterSD.implRead(StreamDecoder.java:298)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:183)
    at java.io.InputStreamReader.read(InputStreamReader.java:167)
    at java.io.Reader.read(Reader.java:122)
    at hoge.foo.bar.my_app.Main.main(Main.java:72)

その「あること」とは、以下のような処理。(DB2 Express-Cに付属のJDBCドライバを使用)

Class.forName("com.ibm.db2.jcc.DB2Driver");

Connection conn = DriverManager.getConnection(
    "jdbc:db2://localhost:50000/sample", "db2admin", "admin");
try {
    PreparedStatement pstmt =
        conn.prepareStatement(
            "SELECT XMLDOCUMENT(XMLELEMENT(NAME \"data\", VAL))"
            + " FROM TABLE(VALUES('きまぐれ日記')) AS T(VAL)");
    ResultSet result = pstmt.executeQuery();
    while (result.next()) {
        DB2Xml db2xml = (DB2Xml) result.getObject(1);
        System.out.println(db2xml.getDB2String()); // これが原因
    }
} finally {
    conn.close();
}

また、IBM製のjdk1.5.0(DB2Express-C v9.1.2に付属)を使用すると、上記の「あること」を実行しなくても例外が発生する。まぁ、こっちの方が妥当な動きだと思うけど。
ちなみに、Sunのjdk1.6.0_01で確認したところ、上記の「あること」を実行しても例外は発生しない。謎だ‥

さて、java.io.CharConversionExceptionをキャッチするのが妥当だと考えているとはいえ、SunのJava VMを使用している限りにおいては例外自体を回避しなければならない場面もあるかもしれない、ということで、ちょっと調べてみた。
まず、確認した範囲では、以下のものは、ダメだった。(変数"result"はjava.sql.ResultSetのインスタンス)

result.getString(1);
DB2Xml db2xml = (DB2Xml) result.getObject(1);
db2xml.getDB2String();
DB2Xml db2xml = (DB2Xml) result.getObject(1);
db2xml.getDB2XmlString();
DB2Xml db2xml = (DB2Xml) result.getObject(1);
Reader r = db2xml.getDB2XmlCharacterStream();

同様に、確認した範囲では、以下は例外が発生しなかったもの。

result.getCharacterStream(1);
DB2Xml db2xml = (DB2Xml) result.getObject(1);
InputStream in = db2xml.getDB2AsciiStream();
DB2Xml db2xml = (DB2Xml) result.getObject(1);
InputStream in = db2xml.getDB2BinaryStream();
DB2Xml db2xml = (DB2Xml) result.getObject(1);
Reader r = db2xml.getDB2CharacterStream();

SunのJava VMで、DB2XML型データの取得を行った際にエラーになるケース、DB2JDBCドライバ内で何が行われているのかが気になるなぁ‥

ちなみに、DB2 Express-C v9.5.2に付属のJDBCドライバを使用すると、SunのJava VMではエラーが発生しなくなる‥もうカオスです‥orz