JRuby+ERB+リフレクションでJavaソースコードの自動生成
Javaのソースコード自動生成が密かに?ブームです。モデルクラスとかサービスのクライアントスタブクラスとかお約束なコードは、がんがん自動生成して楽したい!
ということで、Ruby+ERBでJavaBeanを作るプログラムは前に作ったのですが、あれは「yamlの定義ファイルからソースを作る」仕組みなのでまずYAMLを書けないと使えない。モデルクラスはまぁそれでもいいかと思ったけど、スタブクラスなんかは
みたいにしたい。というか、そうしないとJava使いからクレームがきそうだ。
とはいえ、RubyでJavaインターフェイスのコードを構文解析してどうこうするのはなかなかに敷居が高い。そこでひらめいたのが、
という作戦。ということでインターフェイスを読み込んで、実装クラスを作るサンプルを試しに作ってみました。
インターフェイスを読み込んで実装クラスを作るサンプル
まずは、インターフェイスを読み込んで実装を生成する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がわからなくてしばらくはまったけど、クラス情報にアクセスできるのはとりあえず確認。これでアノテーションとか処理できれば使えるんだけど。ただ、ちょっと見た限りではアクセサが見つからなかったのが気になるところ。要調査です。