05/07/25 1:45 am

Jakarta Commons-LangのExceptionUtilsのメモ

はじめに

JDK1.5(=J2SE 5.0)ではだいぶ標準ライブラリも拡張されてきた。サードパーティのライブラリに頼らずとも多少書き換えれば重宝する。JDK1.3の時代までは例外の中に例外を含めることが出来なかった。これは何を意味するかというと、例外をcatchし何かしらの例外に詰め替えて、throwsし続けると、元の例外の情報がそのままでは、なくなるという事である。SQLExceptionなどはその場で対処するため問題にならないが、フレームワークを開発する場合は、業務では理解できない例外はフレームワークへthrowしてしまえば後は解決できてしまうという構造が望ましい。つまり業務アプリは、例外設計など知らない技術者も実装するからである。

今回は、Jakarta Commons-Lang(英語)をつかって、「例外チェーン」の確認、使い方などを調べてみた。触ってみた感じでは、JDK1.4以降であれば素直に標準の例外機能で問題ないと思う。便利だとおもうのは、入れ子になった例外をメソッド名などで検索できる事ぐらいだ。

それと、Commons-Langのソースコードは綺麗でボリュームも少ないので標準ライブラリのソースコードと比較したりすると非常に勉強になると感じた。例外チェーンの仕組みよりも、Commons-Langのdelegateの仕方が可読性がよく、オブジェクト指向設計としてまとまっていた。またJUnitでリファクタリングしているのを見て、Apache Software Foundationも大規模なベンダーツールよりも、Subversion,JUnitなど基礎部分となる管理ツールを使っているのがシステム開発の参考になった。

この記事にたどり着いた方は是非、自分に必要なものを調べる際はソースコードを入手して学習して欲しい。

 

それと、面倒なので日本語は書かない。ソースコードを読んでください。

 

テスト用ソースコード

/*
 * $Id: ExceptionUtilSample.java 905 2005-07-24 16:24:14Z s-okita $
 *
 * Copyright 2005 satoshiokita. All rights reserved.
 */
 
package org.oklab.apache.commons.lang;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang.exception.NestableException;

/**
 * 実行サンプル
 * @author satoshiokita
 */
public class ExceptionUtilSample {

	public static void main(String[] args) {
		execute();
		
	}

	protected static void execute() {
				try {
					NestableExceptionSample3.a();
					
				} catch (java.lang.RuntimeException e) {
					// 非チェック例外
				} catch (java.lang.Exception e) {
					// 非チェック例外以外(大体はjava.lang.RuntimeException)をcatchする。
					// チェック例外
					
					// EceptionUtilsの各メソッドをテストしている
					// ここまでは、メソッドの抽出をしている
					printCause(e);
					outputAllStackTrace(e);
					printCauseRoot(e);
					printStackAndStackFrame(e);
					printChainException(e);
					printStackLists(e);
					
					// ここからは、まだメソッドの抽出をしていないもの
					
					System.out.println("大元の原因を表示");
					ExceptionUtils.printRootCauseStackTrace(e);
		
					System.out.println("大元の原因をストリームに表示");
					ExceptionUtils.printRootCauseStackTrace(e, System.err);
					
					parseStackStructure(e);
					
					nestableTest(e);
					
					searchThrowable(e);
					

				} catch (java.lang.Error e) {
					// システムエラー
				}
	}

	private static void searchThrowable(java.lang.Exception e) {
		System.out.println("例外を探す検索条件としてmethod名をつけられる。");
		
		String [] methods = { "c" };
		
		
		Throwable z = ExceptionUtils.getCause(e, methods);
		System.out.println(z.getMessage());
	}

	private static void nestableTest(java.lang.Exception e) {
		System.out.println(ExceptionUtils.isNestedThrowable(e));
		
		try { 
			throw new Exception("hogehoge!!");
		} catch (Exception e1) {
			System.out.println(ExceptionUtils.isNestedThrowable(e1));
		}
	}

	private static void parseStackStructure(java.lang.Exception e) {
		System.out.println("例外がStack構造のどこにあるか分かる");
		int result = ExceptionUtils.indexOfThrowable(e, NullPointerException.class);
		System.out.println("result=" + result);
		int result2 = ExceptionUtils.indexOfThrowable(e, NestableException.class);
		System.out.println("result2=" + result2);
		int result3 = ExceptionUtils.indexOfThrowable(e, Exception.class);
		System.out.println("result3=" + result3);
				
	}

	private static void printCauseRoot(java.lang.Exception e) {
		System.out.println("最も上位の例外クラスを取得する");
		System.out.println(ExceptionUtils.getRootCause(e));
	}

	private static void outputAllStackTrace(java.lang.Exception e) {
		System.out.println("例外情報をすべて出力 JDK1.4と変わらない");
		System.out.println(ExceptionUtils.getFullStackTrace(e));
	}

	private static void printStackLists(java.lang.Exception e) {
		System.out.println("スタックのリスト表示");
		Throwable [] expAry = ExceptionUtils.getThrowables(e);
		for ( int i = 0 ; i < expAry.length; i++) {
			(expAry[i]).printStackTrace();
		}
	}

	private static void printChainException(java.lang.Exception e) {
		System.out.println("// TraceCount 例外チェーンの中に例外クラスがいくつ入っているか");
		System.out.println("count=" + ExceptionUtils.getThrowableCount(e));
		
	}

	private static void printStackAndStackFrame(java.lang.Exception e) {
		System.out.println("// Cause Stacktrace");
		String [] ary = ExceptionUtils.getRootCauseStackTrace(e);
		for ( int i = 0; i < ary.length; i++) {
			System.out.println(ary[i]);
			
		}
		
		System.out.println("// StackFrames?");
		String [] frames = ExceptionUtils.getStackFrames(e);
		for ( int i = 0; i < frames.length; i++) {
			System.out.println(frames[i]);
			
		}
	}

	private static void printCause(java.lang.Exception e) {
		System.out.println("// 原因例外の取り出し");
		System.out.println(e.getMessage());
		Throwable c1 = ExceptionUtils.getCause(e);
		System.out.println(c1.getMessage());
		Throwable c2 = ExceptionUtils.getCause(c1);
		System.out.println(c2.getMessage());
	}


}

 

例外をthrowしているテスト対象ソースコード

 

/*
 * $Id: NestableExceptionSample3.java 905 2005-07-24 16:24:14Z s-okita $
 *
 * Copyright 2005 satoshiokita. All rights reserved.
 */
 
package org.oklab.apache.commons.lang;
import java.sql.SQLException;

import org.apache.commons.lang.exception.NestableException;

/**
 * @author satoshiokita
 *
 * この生成されたコメントの挿入されるテンプレートを変更するため
 * ウィンドウ > 設定 > Java > コード生成 > コードとコメント
 */
public class NestableExceptionSample3 {

	public static void main(String[] args) {
		try {
			a();
			
		} catch (java.lang.RuntimeException e) {
			// 非チェック例外
			e.printStackTrace();
		} catch (java.lang.Exception e) {
			// 非チェック例外以外(大体はjava.lang.RuntimeException)をcatchする。
			// チェック例外
			e.printStackTrace();
		} catch (java.lang.Error e) {
			// システムエラー
			e.printStackTrace();
		}
		
	}

	/**
	 * 
	 */
	public static void a() throws Exception {
		try {
			b();
		} catch (Exception e) {
			throw new NestableException("foo", e);
		}
		
	}

	/**
	 * 
	 */
	private static void b() throws Exception {
		try {
			c();
		} catch (Exception e) {
			Exception tmp = new NestableException("bar", e);
			
			throw tmp;
		}	
		
	}

	/**
	 * 
	 */
	private static void c() {
		throw new NullPointerException("exception message in c");
		
	}
}