Java at ミネルヴァの梟は黄昏とともに飛び始める

ミネルヴァの梟は黄昏とともに飛び始める

Follow me on Twitter: http://www.twitter.com/dddaisuke

Archive for the ‘Java’ Category

EJB(CMP)でBlobデータを扱う方法

without comments

 久しぶりにハマりました。

 今まで、SOBA CITYやSOBA mierukaで利用するバイナリデータはディスクスペース(Apacheアクセス領域)で管理していたのですが、データ自体をデータベースで取り扱うようにした方が、管理が楽になるのと、あまり難しい事を考えずにクラスタリングできるようになるとの理由から、バイナリデータをデータベースに押し込む事にしました。

 まず、データをDBに押し込む事は難なくテーブルにBLOB型のカラムを用意してやり、JDBC経由でDBに押し込む。サンプルは、SOBAフレームワークで利用するキーストアをDBに押し込むコード片です。

String sql = “INSERT INTO keystore2s (id, sessionKsr, sessionTks, userKsr, userTks) ”
+ “VALUES (?, ?, ?, ?, ?)”;

PreparedStatement ps = con.prepareStatement(sql);
ps.setString(1, strId);
ps.setBinaryStream(2, sessionKsr, sessionKsr.available());
ps.setBinaryStream(3, sessionTks, sessionTks.available());
ps.setBinaryStream(4, userKsr, userKsr.available());
ps.setBinaryStream(5, userTks, userTks.available());

ps.executeUpdate();

 昔、hibernateが出たての頃にプリミティブ型で表現できないような型はすべてObjectにしかマッピングできなかったという嫌な記憶があり、EJBでもBlob型はObject型にマッピングするのだと勝手に思い込み、実行時に以下のようなマッピングエラーに遭遇し調査に時間がかかりました。

java.sql.SQLException: Unable to load to deserialize result: java.io.StreamCorruptedException: invalid stream header

 EJBでは難しいこと考えずに、単にbyte[]型に直接マッピングできました。

 サーブレットでデータを出力するには、HttpServletResponse#getOutputStream()で、ServletOutputStream を取り出し、ServletOutputStream#write(byte[] data)で出力すればok

 Content-Typeは特に必要ありませんが、気になる方は「text/plain」を指定したら良いですよ。

Written by daisuke

4月 22nd, 2008 at 8:43 pm

Java の URLEncoder / URLDecoder で文字化けする問題

with 3 comments

 最近、バタバタしていてあまり記事を投稿できていませんでしたが久し振りの投稿です。

CGIでURLエンコードした文字列をJavaでURLデコードするとなぜか日本語の一部が文字化けする問題が発生していました。色々と調べていると、Perlでは2バイトコードかどうかに関係なく、1バイトずつ文字列をURLエンコードするのに対し、Javaは2バイトコードのみをURLエンコードしていることが分かりました。

ただ、どちらが間違いという事は無く、両方ともエンコーダーの実装としては正しいみたいです。ただし、Javaのデコーダーの実装が良くないみたいで、PerlでURLエンコードした文字列を正確に文字列に戻せない不具合があるようです。

しょうがないので、以下のように自前で正常に動作するURLDecoderを作成しました。


 続きを読む »

Written by daisuke

11月 12th, 2007 at 10:31 pm

Posted in Java

Javaでクラスパスを動的に追加する方法 2

without comments

この実行結果を見る限り、”java.class.path”に必要なパスを追加してやればイイじゃん!と安易に思ってしまうのですが、これが失敗の始まりです。

Javaのクラスローダは起動時にクラスパスを確定してしまうので、安直に『System.setProperty』ではクラスパスを改変する事ができません。(クラスローダの詳しい仕組みについてはこちらをご覧下さい

で、結局リフレクションで無理やりパスを追加する事になります。


package com.daisukeyamashita.util;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

@SuppressWarnings("unchecked")
public class ClassPathModifier {

    private static final Class[] parameters = new Class[] { URL.class };

    public static void addFile(String s) throws IOException {
        File f = new File(s);
        addFile(f);
    }

    public static void addFile(File f) throws IOException {
        addURL(f.toURL());
    }

    public static void addURL(URL u) throws IOException {
        URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();

        Class sysclass = URLClassLoader.class;

        try {
            Method method = sysclass.getDeclaredMethod("addURL", parameters);
            method.setAccessible(true);
            method.invoke(sysloader, new Object[] { u });
        } catch (Throwable t) {
            throw new IOException("could not add " + u + " to classpath");
        }
    }
}

Written by daisuke

10月 24th, 2007 at 3:30 pm

Posted in Java