Javaで例外発生後に例外メッセージを変更する方法

java

例外オブジェクトにはメッセージが格納されており、getMessage()メソッドでそのメッセージを取得することができます。
しかし、このメッセージはコンストラクタでのみ設定可能であり、メッセージを後で変更するメソッドは用意されていないため、例外クラスに用意されている手段では例外発生後にメッセージを書き変えることはできません。

しかし、リフレクションを使用することで、メッセージを後で書き変えることが可能です。
メッセージはThrowableクラスのprivateのクラス変数”detailMessage”に保持されるため、これをリフレクションで書き変えます。

サンプルコードは以下の通りです。

【サンプルコード】

・ExceptionTest.java

【実行結果】

・コンソール(標準出力)

・コンソール(標準エラー出力)


ちなみに、リフレクション時に発生してしまう標準エラー出力ですが、(試していませんが)Java8では出ないようです。
筆者の環境(Java10)だと出てしまいます。

そこで以下の2つの手段を試しましたが、何れもエラー抑止はできませんでした。

1.JVM引数で抑止

“–illegal-access=deny”を指定したら逆に異常終了するようになってしまいました。

2.標準エラー出力の出力ストリームを変更

通常、”System.setErr(自作PrintStreamオブジェクト);”を記述することで標準エラー出力の出力先を変更し、コンソールに出力されないようにすることができるのですが、今回のケースではそれができませんでした。
“System.err.close();”を記述した場合はコンソールへの出力を抑止することができたので、リフレクション時のWARNINGメッセージでは”System.err”を直接使用しているのではないかと思います。
なお、”System.err”はクローズしたらリオープンすることができないので、”System.err.close();”を実行してしまうと、以降は予期せぬ例外等が発生しても標準エラー出力として出力できなくなってしまいます。
(”System.err.close();”を実行した後に”System.setErr(System.out);”を実行して、予期せぬ例外等も全て標準出力として出力することならできますが…)


いかがでしたでしょうか。

今回の記事では、例外発生時のメッセージを後から書き変えられることを確認しましたが、標準エラー出力が出力されることを考えると、このようなソースコードはできる限り書くべきではないと思います。
どうしても書き変え可能な変数を伝播させたいのであれば、独自例外クラスに独自のクラス変数を定義してそれを伝播させる等の工夫をするべきだと思います。

コメント

タイトルとURLをコピーしました