2011年9月4日日曜日

OracleのBLOBにJavaオブジェクトを保存

OracleデータベースのBLOB型のカラムにJavaオブジェクトを保存する方法。


サンプルコード

データベース定義

SQL> desc blob_test

 Name                                      Null?    Type
 ----------------------------------------- -------- ----------------------------
 ID                                        NOT NULL CHAR(5)
 OBJECT_DATA                                        BLOB

データベースへの保存方法

        // DBへ保存するオブジェクトを生成
        // DBへ保存するオブジェクトは直列化可能でなければならない。
        // (Serializableをimplementsする必要がある)
        HogeInfo info = new HogeInfo();
        info.setId("ID");
        info.setName("なまえ");

        // 上記で生成したオブジェクトを直列化し、OutputStreamへ書き出す。
        // この例だと、ByteArrayOutputStreamに出力をしている。
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream stream = new ObjectOutputStream(out);
        stream.writeObject(info);

        PreparedStatement preparedStatement = con.prepareStatement(
                "insert into blob_test (id, OBJECT_DATA) values (?, ?)");

        try {
            preparedStatement.setString(1, "00001");
            // ByteArrayOutputStreamに出力したオブジェクトの情報を、byte配列で取得し
            // BLOBカラムにバインドする。
            preparedStatement.setBytes(2, out.toByteArray());
            preparedStatement.executeUpdate();
        } finally {
            preparedStatement.close();
        }

データベースからの取得方法

        PreparedStatement preparedStatement = connection.prepareStatement(
                "select object_data from blob_test where id = '00001'");
        byte[] bytes;
        try {
            ResultSet resultSet = preparedStatement.executeQuery();
            resultSet.next();
            // BLOBカラムの値をbyte配列で取得
            bytes = resultSet.getBytes(1);
        } finally {
            preparedStatement.close();
        }

        // 取得したオブジェクトをObjectInputStreamを使ってデシリアライズする。
        ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
        HogeInfo hogeInfo = (HogeInfo) objectInputStream.readObject();

        // デシリアライズしたオブジェクトの属性を出力
        System.out.println("hogeInfo.getId() = " + hogeInfo.getId());
        System.out.println("hogeInfo.getName() = " + hogeInfo.getName());

実行結果

保存したオブジェクトの属性が、復元できていることが分かる。
hogeInfo.getId() = ID
hogeInfo.getName() = なまえ

2011年8月25日木曜日

Intellijでscala開発

IntellijにScala開発環境を導入する手順

scalaライブラリのダウンロード

下記サイトからscalaのライブラリをダウンロードしておきます。
http://www.scala-lang.org/downloads

ダウンロードしたDistributionは、任意のディレクトリに解凍しておきます。

Intellijのscalaプラグインをインストール

プラグインのインストール画面からscalaプラグインをインストールします。インストール後にIntellijを再起動する必要があります。

scalaプロジェクトの作成

1.「File」→「New Project」を選択

2.Create project from scratchを選択して次(Next)へ

3.プロジェクトを作成したいディレクトリを「Project file location」に入力して、select typeは、「Java Module」を選択します。


4.下記画面が表示されるまで次へ移動します。

5.下の画像のようにscalaを選択して、「use scala distribution」に、最初にダウンロードして解凍しておいたディレクトリを入力します。


6.「Finish」をクリックするとScalaプロジェクトの作成終了です。


hello worldってみる

「src」ディレクトリを右クリックし、「New」から「scala script」を選択する。

ファイル名を入力するダイアログが表示させるので任意のスクリプト名を入力。ここでは、ファイル名を「test.scala」としています。

エディタで、下記コードを入力する。

println("hello world.")


作成したスクリプトを実行するには、「F9」を押下するかメニューから「Run」→「Edit Configurations」を選択します。
選択すると下記画面が表示されるので「test.scala」を選択してEnterでスクリプトを実行します。


実行すると下記のようなRunウィンドウが表示され実行結果(hello world.)が表示されます。


これでscalaプロジェクトが正しく作成されたことが確認できたので、Intellijのscalaな開発環境でscalaをごりごり書いちゃいましょう。


追記
一時期Scala scriptの実行がIntellijから行えなかったけど、10/28にリリースされたpluginを適用すれば解消しています。

2011年8月23日火曜日

scala本を購入

scala本を購入してみた。

まだ少ししか読んでないけど、日本人の方が書いているので非常にわかりやすいと思います。
Scala初心者は下手な翻訳本を買うなら、この本の前半部で十分ではないかと思います。


2011年8月21日日曜日

Intellijの便利な正規表現編集

Javaソースコード上で正規表現を書く場合に、Javaのエスケープと正規表現のメタ文字に対するエスケープが同じ文字(\)なので、非常に面倒に思う場面がある。

その面倒な部分をうまく解消してくれる地味だけど非常に便利な正規表現編集機能がIntellijにはあります。

使用方法

正規表現部分にカーソルを移動して、クイックフィックスから「Edit RegExp Format」を選択する。
正規表現を編集するためのエディタが新規に開かれるので、正規表現を編集する。
この時には、Java文字列に対するエスケープは考えずに書けば良い。なので、純粋に正規表現のことだけを考えればよく直感的にコーディングが出来る。
また、正規表現がすでに書かれた状態でこのエディタ(Edit RegExp Format)を選択した場合も、Javaのエスキープ文字が削除されているので、正規表現を確認するときにも使うことができる。
画面的には、こんな感じになっている。


上記画面で編集を行っていると、リアルタイムにJavaコードに正規表現が反映されていきます。編集が終わったあとは「Esc」ボタンで閉じることが出来ます。
上記画面の正規表現がJavaコードに反映されると、Javaのエスケープ文字が追加されているのがわかります。

Intellijのすごいところは、正規表現を文字列定数とかで持っていても、この文字列は正規表現であると判断してこんな感じにクイックフィックスを表示してくれることです。

ここまでの例では、すべてJDK付属の正規表現ライブラリを使用していまいしたがオープンソースや自作の正規表現ライブラリに対しても上記と同じことができます。
例えば、こんな感じのクラスのsetRegexの引数を正規表現としたい場合の例
class HogeRegex {

    public void setRegex(String regex) {
        
    }
}
Settings画面から、Language Injectionを選択します。画面的には、こんな画面が表示されます。

「+」ボタンをクリックして「Java Parameter」を選択します。
表示されるサブウィンドウに下記のように入力します。
ID:RegExpを選択
Class-Name:正規表現ライブラリのクラス名入力する。(今回の例だとHogeRegexを入力する。)
Parameters:メソッド一覧とメソッドの持つパラメータ一覧が表示されるので正規表現を引数で受け取るパラメータにチェックを入れる。
設定を終えると、JDKのライブラリを使ったときと同じようにクイックフィックスに「Edit RegExp Format」が表示されるようになります。

ちなみにPatternクラスも、Language Injectionにちゃんと登録されていたりします。




2011年8月7日日曜日

rubyのリフレクション

eval

eval関数を使うと、指定した式を評価することができる。
式を文字列として指定するので、構文エラーとなるような文字列を指定したら例外が発生する。

使用例

# 計算を実行
eval("1 + 2")        # -> 3
eval("1 * 2")        # -> 2

# 変数を使用して計算の実行
num = 100
eval("num + num")    # -> 200

# 変数に値を設定
class Hoge
  attr_accessor :id
end

# idプロパティに値を設定
hoge = Hoge.new
eval("hoge.id=100")
puts hoge.id     # -> evalで設定された100が取得される

# インスタンス変数の宣言
eval("@hogehoge = 'hoge'")
puts @hogehoge   # -> @hogehogeが参照でき、'hoge'が取得できる。

# ローカル変数の宣言
# eval内で宣言されたローカル変数のスコープは、evalの処理を抜けたら参照できない。
eval("hogehoge = 12345; puts hogehoge")    # -> ここでは、ローカル変数を参照できる。

begin
  # evalを抜けているので参照すると、未定義ですよエラーが発生する
  puts hogehoge           
rescue => e
  puts e.message
end


インスタンスに対する操作

任意のインスタンス(クラス)のインスタンス変数やクラス変数の値参照や値設定方法

例

# インスタンス変数の操作
object = Object.new
# nameインスタンス変数は、存在していないのでfalse
object.instance_variable_defined?(:@name)
# nameインスタンス変数に値(instance_variable)を設定
object.instance_variable_set(:@name, "instance_variable")
# instance_variable_getが返される
object.instance_variable_get(:@name)
# nameインスタンス変数が追加されたのでtrue
object.instance_variable_defined?(:@name)
# nameインスタンス変数を削除
object.instance_eval { remove_instance_variable :@name }
# nameインスタンス変数は削除されたのでfalse
object.instance_variable_defined?(:@name)

# クラス変数に値をセット(宣言されていなければ追加される。)
# nameクラス変数は存在していないのでfalse
puts Object.class_variable_defined? :@@name
# nameクラス変数に値(class_variable)を設定
Object.class_variable_set(:@@name, "class_variable")
# class_variable_getが返される
puts Object.class_variable_get(:@@name)
# nameクラス変数が追加されたのでtrue
puts Object.class_variable_defined? :@@name
# nameクラス変数を削除
Object.class_eval { remove_class_variable :@@name }
# nameクラス変数は削除されたのでfalse
puts Object.class_variable_defined? :@@name

メソッドに対する操作

メソッド一覧の参照や、メソッドの実行ができる。また、動的にインスタンスにメソッドを追加することもできたりする。

例

object = Object.new
# public_methodsでも同じことができる。
object.methods
# 継承したメソッドを除外(自クラスで宣言したメソッドのみが出力される。)
# trueにすると、methodsと同じ動きになる。ちなみに引数省略した場合は、true
object.public_methods false

# 他にも、private_methodsやprotected_methodsがある。

# 特異メソッドの定義(このインスタンスのみがもつメソッド)
def object.hoge
  "fuga"
end
object.hoge
object.public_methods false

# メソッド呼び出し
hoge = "hogehoge"
hoge.send(:upcase)   # upcaseメソッドの呼び出し(メソッドは、シンボルとして指定する。)


2011年7月31日日曜日

java7とIntellij

Java7がリリースされたので、Intelijへの設定のまとめ。

SDKの追加

1.Project Structureを開く(「File」→「Project Structure」)
2.左側のメニューから「SDKs」を選択する。
3.「+」ボタンからjava7をSDKとして追加する。下の画像のように「+」ボタンで出てきたメニューから「JSDK」を選択する。
    4.Select Pathのサブウィンドウが表示されるので、java7のインストールディレクトリ(JAVA_HOME)を設定する。

    java7用のモジュールを作成

    1.Dependenciesタブを選択して、モジュールで使用するJDKを1.7に変更する。

    2.Sourcesタブを選択して、Language levelを7.0に変更する。

    java7用のInspectionを使ってみる

    Autoclosableへの置換え

    java6までのリソース管理(try-finallyでのリソース解放処理)を、java7のautoclosableに置き換えるInspectionを有効にすると、Quick Fixからautoclosableへの自動置き換えが可能となる。

    【変更前のコード】
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Hoge {
    
        public static void main(String... args) throws IOException {
    
            FileOutputStream stream = new FileOutputStream("hoge.txt");
            try {
                stream.write(0);
            } finally {
                stream.close();
            }
        }
    }
    

    【Quick Fixの実行】
    「Replace with 'try' with resources」を実行する。

    【置き換え後のコード】
    自動で下のコードに置き換えが実行される。
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Hoge {
    
        public static void main(String... args) throws IOException {
    
            try (FileOutputStream stream = new FileOutputStream("hoge.txt")) {
                stream.write(0);
            }
    
        }
    }
    

    これ以外のもこんなこともできるメモ。
    http://se-bikou.blogspot.com/2011/04/intellijjdk7.html

    2011年7月2日土曜日

    rubyのメソッド引数

    rubyのメソッド引数のまとめ

    通常の引数

    通常の引数をもつメソッド。当然ながら最も多く利用されると思われる。
    def print_message message
      print "[#{message}]"
    end
    

    デフォルト値をもつ引数

    デフォルト値をもつことでクライアントコードを簡略化できる。
    javaでオーバーロードを行い、引数の多いメソッドに固定値を渡すパターンの場合この実装で代用することが可能。
    ※rubyではオーバーロードを行うことができないので、デフォルト値を持つ引数をつかって実現するほかない。
    # p2を省略するとデフォルト値の0が適用される。
    def m1 p1, p2 = 0
      p1 + p2
    end
    
    m1 1      # p2を省略した場合
    m1 1, 2   # 明示的に指定した場合
    
    # p1を省略するとデフォルト値の1が適用される。
    def m2 p1 = 1, p2
      puts p1 + p2
    end
    
    m2 1      # p1を省略した場合
    m2 1, 2   # 明示的に指定した場合
    
    # p1を省略するとデフォルト値の1が適用される。
    # p2を省略するとデフォルト値の2が適用される。
    def m3 p1 = 1, p2 = 2
      puts p1 + p2
    end
    
    m3        # p1、p2を省略した場合
    m3 1      # p1を省略した場合
    m3 1, 2   # 明示的に指定した場合
    
    # 引数は、左から設定されるのでp1を省略してp2のみ値を指定することはできない。
    

    可変引数

    # 可変長引数は、変数名の前に「*」をつける。
    def hoge(*hoge)
      hoge.each do |val|
        puts val
      end
    end
    
    hoge("1", "2", "3")
    

    名前付き引数

    名前付き引数というのかわからないけど、引数を指定する際に名前をつけることができる。
    実際には、Hashで受け渡しを行うのだけれど、RubyのHashは簡易的にインスタンス化できるので、
    あたかも引数名に値を設定するかのように実装することができる。
    def m(args)
      puts "p1 : #{args[:p1]}"
      puts "p2 : #{args[:p2]}"
    end
    
    m p1:"hoge", p2:["fuga1", "fuga2"]