外部のクラスのmain()を呼んだりしてみたところ、System.exit()されて後続の処理をキャンセルされてしまいました。それでは困るので、セキュリティマネージャーの力を借りてみました。
// 現在のセキュリティマネージャを取得 final SecurityManager originalManager = System.getSecurityManager(); // 新しいセキュリティマネージャを作る System.setSecurityManager(new SecurityManager() { // exitされたくない public void checkExit(int code){ throw new MyExitException(code, "can not exit."); } // 他の操作は元のセキュリティマネージャにお願い public void checkPermission(Permission perm){ if(originalManager != null) originalManager.checkPermission(perm); } // 他の操作は元のセキュリティマネージャにお願い public void checkPermission(Permission perm, Object obj) { if(originalManager != null) originalManager.checkPermission(perm, obj); } }); Exception occured = null; try{ // 外部のメインルーチンを呼ぶ Outerclass.main(new String[] {"arg1", "arg2"}); }catch(MyExitException mee){ // exitされた if(mee.getCode() != 0) occured = mee; // exitの戻り値が正常終了( = 0 )ならNOP }catch(Exception e){ // 例外が投げられた occured = e; }finally{ // セキュリティマネージャを戻す System.setSecurityManager(originalManager); } if(occured != null){ /* 思う存分エラー処理 */ ... }
checkPermission()しか上書きしてない辺りがひじょーに自信ないので、クリティカルな場面ではjavaのセキュリティについてよく調べてから使ったほうが吉です。後、SecurityManagerの上書きができない状態になってることもあるので、そのときは諦めましょうorz。*1
いらないと思うけど、内部クラスのMyExitExceptionも載せときます。
static private class MyExitException extends RuntimeException{ private final int code; MyExitException(int code){ this(code, null); } MyExitException(int code, String message){ this(code, message, null); } MyExitException(int code, String message, Throwable th){ super(message, th); this.code = code; }; int getCode(){ return code; } }
*1:後、Errorは潔く諦めてますが、それもなんとかしたければThrowableで。