読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

JRuby+ERB+リフレクションでJavaソースコードの自動生成

Ruby Java

Javaソースコード自動生成が密かに?ブームです。モデルクラスとかサービスのクライアントスタブクラスとかお約束なコードは、がんがん自動生成して楽したい!

ということで、Ruby+ERBでJavaBeanを作るプログラムは前に作ったのですが、あれは「yamlの定義ファイルからソースを作る」仕組みなのでまずYAMLを書けないと使えない。モデルクラスはまぁそれでもいいかと思ったけど、スタブクラスなんかは

  1. Javaでサービスインターフェイスを書く!
  2. ツールを実行

みたいにしたい。というか、そうしないとJava使いからクレームがきそうだ。

とはいえ、RubyJavaインターフェイスのコードを構文解析してどうこうするのはなかなかに敷居が高い。そこでひらめいたのが、

  1. JRuby+リフレクションでJavaクラスにアクセス
  2. 読み込んだ情報を元にERBでソースコード生成

という作戦。ということでインターフェイスを読み込んで、実装クラスを作るサンプルを試しに作ってみました。

インターフェイスを読み込んで実装クラスを作るサンプル

まずは、インターフェイスを読み込んで実装を生成するJRubyコード(read-interface.rb)。java.util.Mapの実装を自動生成します。

require 'erb'
require 'java'

# ERB
erb = ERB.new(IO.read("./impl.erb"), nil, "%" )

# インターフェイスをインポート
import 'java.util.Map'
clazz = Map.java_class # java_classでJavaのクラスがとれるらしい。

# 実装スタブの生成
puts erb.result(binding)

ERB(impl.erb)は次の通り。適当です。

/**
 * {@link <%= clazz.name %>}
 *
 * @version $Revision:$
 * @author  $Author:$
 */
public class <%= clazz.simple_name %>Impl implements <%= clazz.name %> {

% clazz.java_instance_methods.each{|m|
    public <%= m.return_type != nil ? m.return_type : "void" %> <%= m.name %>( <%= i=0;m.argument_types.map!(){|arg| i+=1; arg.to_s + " arg" + i.to_s }.join(", ") %> ){
    	// auto generate
% if m.return_type != nil
%   if m.return_type.name == "int" || m.return_type.name == "long"
    	return 0;
%   elsif m.return_type.name == "boolean"
    	return false;
%   else
    	return null;
%   end
% end
    }
% }

}

実行!

jruby read-interface.rb > MapImpl.java

実行結果です。

/**
 * {@link java.util.Map}
 *
 * @version $Revision:$
 * @author  $Author:$
 */
public class MapImpl implements java.util.Map {

    public int hashCode(  ){
    	// auto generate
    	return 0;
    }
    public java.lang.Object put( java.lang.Object arg1, java.lang.Object arg2 ){
    	// auto generate
    	return null;
    }
    public void clear(  ){
    	// auto generate
    }
    public boolean equals( java.lang.Object arg1 ){
    	// auto generate
    	return false;
    }
    public java.util.Set entrySet(  ){
    	// auto generate
    	return null;
    }
    public java.lang.Object get( java.lang.Object arg1 ){
    	// auto generate
    	return null;
    }
    public void putAll( java.util.Map arg1 ){
    	// auto generate
    }
    public int size(  ){
    	// auto generate
    	return 0;
    }
    public java.util.Collection values(  ){
    	// auto generate
    	return null;
    }
    public java.lang.Object remove( java.lang.Object arg1 ){
    	// auto generate
    	return null;
    }
    public boolean containsKey( java.lang.Object arg1 ){
    	// auto generate
    	return false;
    }
    public boolean containsValue( java.lang.Object arg1 ){
    	// auto generate
    	return false;
    }
    public boolean isEmpty(  ){
    	// auto generate
    	return false;
    }
    public java.util.Set keySet(  ){
    	// auto generate
    	return null;
    }

}

java_classとjava_instance_methodsがわからなくてしばらくはまったけど、クラス情報にアクセスできるのはとりあえず確認。これでアノテーションとか処理できれば使えるんだけど。ただ、ちょっと見た限りではアクセサが見つからなかったのが気になるところ。要調査です。