プログラムdeタマゴ

nodamushiの著作物は、文章、画像、プログラムにかかわらず全てUnlicenseです

jshellを自分のプログラムに組み込みたかった

はい。タイトルの通りです。しょーもないことしてました。


jshell

JDK9から付属することになっているちまたで話題のJavaのREPL。
私は全く興味がなかったんですけど、ふと思ったんですよ。これ自分のプログラムに組み込めないかな?


GUI系のプログラムは毎回実行して動作確認して終了して直して実行して………が面倒くさいんですよ。
JavaScriptとかGroovyとかを実行できるような簡易GUIを搭載したりしてそこでチマチマ弄れるようにしたりしてるんですけど、これをjshellに置き換えられないかな?と調べてみました。


自分のプログラム内部でJShellを作成して実行する

JShellは以下のような感じで作成できるようです。

try(JShell shell = jdk.jshell.JShell.create()){
}

 というわけで、以下のようなコードを試してみました。

package test;

import java.util.List;
import jdk.jshell.*;

public class TestApplication {
    
    public static String PRINT = "------Not Change-------";
    
    public String method(){//JShellでこのメソッドを呼ぶ
        System.out.println(PRINT);
        return "Test Application";
    }
    
    public static void main(String[] args){
        PRINT = "Print this text?";//ここでPRINTを入れ替えている
        try(JShell shell = JShell.builder()
                //err,outで出力先を変えられる
                .err(System.out)
                .out(System.err)
                .build()){
            shell.addToClasspath(System.getProperty("java.class.path"));
            List<SnippetEvent> evs =  shell.eval("new test.TestApplication().method();"); 

            for(SnippetEvent e:evs){
                if (e.causeSnippet() == null) {
                    switch (e.status()) {
                        case VALID:
                            if(e.value()!=null)
                                System.out.println("eval result = "+e.value());
                            else
                                System.out.println("Success.(no result)");
                            break;
                    }
                }
            }
        }
    }
}

 もし、私の望み通りの動作をするならば、「Print this text?」という文字が出力された後に、「eval result = Test Application」となるはずです。

結果

f:id:nodamushi:20161130221852p:plain

 ………残念でした。------Not Change-------とプリントされてしまいました。
 つまり、JShellエンジンではmain関数は実行されていないことになっているのです。(main関数の一番最初にPRINT変数を入れ替えている)


 どうもJShellは実行時にもう一個別のJVMを立ち上げて、そちらをリモートで操作するような処理をしているようです。
 上記のプログラムのmethod()でsleepするように書き換えてから実行すると、2個Javaのプロセスが増えるのを確認できます。

f:id:nodamushi:20161130221853p:plain


それでもjshellを組み込みたい

>jshell -cp 必要なクラスパス

jshell>test.TestApplication.main(new String[0]);

ん~~………