001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.system; 017 018import java.util.List; // 6.9.2.1 (2018/03/12) 019import java.util.ArrayList; // 6.9.2.1 (2018/03/12) 020import java.util.Set; // 6.9.2.1 (2018/03/12) 021import java.util.HashSet; // 6.9.2.1 (2018/03/12) 022 023import java.util.concurrent.ConcurrentMap; // 6.4.3.3 (2016/03/04) 024import java.util.concurrent.ConcurrentHashMap; 025 026import static org.opengion.fukurou.system.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 027import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE; // 6.4.2.0 (2016/01/29) 028 029/** 030 * ThrowUtil.java は、共通的に使用される Throwable,Exception関連メソッドを集約した、クラスです。 031 * 032 * StringUtil にあったメソッドを、こちらに移動させました。 033 * 034 * @og.group ユーティリティ 035 * 036 * @og.rev 6.4.2.0 (2016/01/29) 新規作成 037 * @og.rev 6.4.3.2 (2016/02/19) 全面書き換え 038 * 039 * @version 6.0 040 * @author Kazuhiko Hasegawa 041 * @since JDK8.0, 042 */ 043public final class ThrowUtil { 044 public static final int MIN_STACK_SIZE = 3; // 先頭から、通常にスタックトレースする行数。 045// public static final int NOMAL_STACK_SIZE = 5; // 先頭から、通常にスタックトレースする行数。 046// public static final int UNLIMITED_SIZE = -1; // スタックトレースする行数。-1 は、制限なし 047 048 // 6.9.2.1 (2018/03/12) 複数個所で呼ばれた場合の処理が、うまく出来ないので、暫定対策。(同時起動で、混ざる) 049 private static final CaseBuilder C_BUF = new CaseBuilder(); 050 051 // 6.9.3.0 (2018/03/26) static で持ちます。 052 private static final StackTraceElement NULL_STE = new StackTraceElement( "","","",-1 ); 053 054 /** 055 * デフォルトコンストラクターをprivateにして、 056 * オブジェクトの生成をさせないようにする。 057 * 058 */ 059 private ThrowUtil() {} 060 061 /** 062 * Throwable の printStackTrace() 結果の内、opengion に関する箇所だけを文字列に変換して返します。 063 * 064 * @og.rev 6.4.2.0 (2016/01/29) StringUtil にあったメソッドを移動。 065 * @og.rev 6.4.2.0 (2016/01/29) すべてのスタックトレースを行っていたが、絞り込みます。 066 * 067 * @param th printStackTraceすべき元のThrowableオブジェクト 068 * 069 * @return Throwableの詳細メッセージ( th.printStackTrace() ) 070 */ 071 public static String ogStackTrace( final Throwable th ) { 072 return ogStackTrace( null , th ); 073 } 074 075 /** 076 * Throwable の printStackTrace() 結果の内、opengion に関する箇所だけを文字列に変換して返します。 077 * 078 * printStackTrace() すると、膨大なメッセージが表示されるため、その中の、"org.opengion" を 079 * 含む箇所だけを、抜粋します。 080 * また、同じ内容のエラーも除外します。 081 * 先頭から、MIN_STACK_SIZE 行は、元のままのメッセージを出力します。 082 * Throwable#getCause() で、再帰的に原因をさかのぼります。 083 * 084 * @og.rev 5.7.2.0 (2014/01/10) 新規作成 085 * @og.rev 6.4.2.0 (2016/01/29) StringUtil にあったメソッドを移動し、msg 引数を追加。 086 * @og.rev 6.4.3.2 (2016/02/19) (通常try-with-resources文によって)抑制された例外も出力します。 087 * @og.rev 6.5.0.1 (2016/10/21) メッセージに、BuildNumber.ENGINE_INFO を含める。 088 * @og.rev 6.9.0.1 (2018/02/05) causeの対応が中途半端だったので、修正します。 089 * @og.rev 6.9.2.1 (2018/03/12) 最小件数のbreak判定の方法を見直します。 090 * 091 * @param msg 合成したいメッセージ 092 * @param th 元のThrowableオブジェクト 093 * 094 * @return Throwableの詳細メッセージ( StackTraceElement の抜粋 ) 095 */ 096 public static String ogStackTrace( final String msg,final Throwable th ) { 097// final CaseBuilder buf = new CaseBuilder() 098 C_BUF.init() 099 .append( "Version: " , BuildNumber.ENGINE_INFO ) // 6.5.0.1 (2016/10/21) エンジンのバージョン 100 .append( "Message: " , msg ); // 追加メッセージ 101 102 if( th != null ) { 103 // final CaseBuilder buf = new CaseBuilder() 104 // .append( "Version: " , BuildNumber.ENGINE_INFO ) // 6.5.0.1 (2016/10/21) エンジンのバージョン 105 // .append( "Message: " , msg ) // 追加メッセージ 106 // Throwable.toString() で、クラス名とメッセージを分けて、それぞれを重複チェックする。 107 C_BUF.append( "Error : " , th.getClass().getCanonicalName() ) // クラス名 108 .append( " " , th.getLocalizedMessage() ) // メッセージ 109// .addStackTrace( th , MIN_STACK_SIZE , UNLIMITED_SIZE ); 110 .addStackTrace( th , MIN_STACK_SIZE ); // 6.9.2.1 (2018/03/12) 111 112 // 原因の Throwable 113 Throwable tmpTh = th.getCause(); 114 while( tmpTh != null ) { 115 C_BUF.append( "Cause : " , tmpTh.getClass().getCanonicalName() ) // クラス名 116 .append( " " , tmpTh.getLocalizedMessage() ) // メッセージ 117// .addStackTrace( tmpTh , 0 , UNLIMITED_SIZE ); // 最小行は指定しない。 118 .addStackTrace( tmpTh , MIN_STACK_SIZE ); // 6.9.2.1 (2018/03/12) 119 120 tmpTh = tmpTh.getCause(); 121 } 122 123 // 6.4.3.2 (2016/02/19) (通常try-with-resources文によって)抑制された例外も出力します。 124 // このThrowable は、原因の Throwable は、求めません。 125 for( final Throwable supTh : th.getSuppressed() ) { 126 C_BUF.append( "Suppressed : " , supTh.getClass().getCanonicalName() ) // クラス名 127 .append( " " , supTh.getLocalizedMessage() ) // メッセージ 128// .addStackTrace( supTh , 0 , UNLIMITED_SIZE ); 129 .addStackTrace( supTh , MIN_STACK_SIZE ); // 6.9.2.1 (2018/03/12) 130 } 131 } 132 133// return buf.toString(); 134 return C_BUF.toString().trim(); 135 } 136 137 /** 138 * 発生元を示すクラス、メソッド、行番号とともに、メッセージを合成した文字列を返します。 139 * 140 * 通常、System.out.println() で済ましていたエラーメッセージに対して、 141 * エラー発生場所を特定する為の情報を付与したメッセージを作成します。 142 * 発生場所の行番号は、このメソッド(実施は、オーバーロード先)で new Throwable して、取得します。 143 * 呼ぶ場所で、new Throwable() する代わりの簡易目祖度になります。 144 * 145 * @og.rev 6.4.2.0 (2016/01/29) 新規作成。 146 * 147 * @param msg 合成したいメッセージ 148 * 149 * @return 発生元を示すクラス、メソッド、行番号とともに、メッセージを合成した文字列 150 */ 151 public static String ogThrowMsg( final String msg ) { 152 return ogThrowMsg( msg , null ); 153 } 154 155 /** 156 * 発生元を示すクラス、メソッド、行番号とともに、メッセージを合成した文字列を返します。 157 * 158 * 通常、System.out.println() で済ましていたエラーメッセージに対して、 159 * エラー発生場所を特定する為の情報を付与したメッセージを作成します。 160 * 行番号は、引数のThrowableの最初の情報のみ使用する為、通常は、このメソッドを 161 * 呼ぶ場所で、new Throwable() します。 162 * 発生クラスは、org.opengion か、org.apache.jsp.jsp を含む3行のみの簡易メッセージとします。 163 * 164 * @og.rev 6.3.6.1 (2015/08/28) 新規作成 165 * @og.rev 6.3.6.1 (2015/08/28) メッセージに、th.getLocalizedMessage() を含める。 166 * @og.rev 6.3.9.0 (2015/11/06) thのnullチェックを先に行う。 167 * @og.rev 6.4.2.0 (2016/01/29) StringUtil にあったメソッドを移動するとともに、メソッド名を、ogErrMsg → ogThrowMsg に変更。 168 * @og.rev 6.5.0.1 (2016/10/21) メッセージに、BuildNumber.ENGINE_INFO を含める。 169 * @og.rev 6.9.0.1 (2018/02/05) causeの対応が中途半端だったので、修正します。 170 * @og.rev 6.9.2.1 (2018/03/12) 最小件数のbreak判定の方法を見直します。 171 * 172 * @param msg 合成したいメッセージ 173 * @param th 元のThrowableオブジェクト 174 * 175 * @return 発生元を示すクラス、メソッド、行番号とともに、メッセージを合成した文字列 176 */ 177 public static String ogThrowMsg( final String msg,final Throwable th ) { 178// final CaseBuilder buf = new CaseBuilder() 179 C_BUF.init() 180 .append( "Version: " , BuildNumber.ENGINE_INFO ) // 6.5.0.1 (2016/10/21) エンジンのバージョン 181 .append( "Message: " , msg ); // 追加メッセージ 182 183 if( th != null ) { 184 C_BUF.append( "Error : " , th.getClass().getCanonicalName() ) // クラス名 185 .append( " " , th.getLocalizedMessage() ); // メッセージ 186// .addStackTrace( th , MIN_STACK_SIZE , MIN_STACK_SIZE ); 187 // .addStackTrace( th , MIN_STACK_SIZE ); // 6.9.2.1 (2018/03/12) 188 189// final Throwable cause = th.getCause(); // 原因の Throwable (1回だけ) 190// if( cause != null ) { 191// buf.append( "Cause : " , cause.getClass().getCanonicalName() ) // クラス名 192// .append( " " , cause.getLocalizedMessage() ); // メッセージ 193//// .addStackTrace( cause , MIN_STACK_SIZE , MIN_STACK_SIZE ); 194// // .addStackTrace( cause , MIN_STACK_SIZE ); // 6.9.2.1 (2018/03/12) 195// } 196 197 // 原因の Throwable 198 Throwable tmpTh = th.getCause(); 199 while( tmpTh != null ) { 200 C_BUF.append( "Cause : " , tmpTh.getClass().getCanonicalName() ) // クラス名 201 .append( " " , tmpTh.getLocalizedMessage() ); // メッセージ 202 203 tmpTh = tmpTh.getCause(); 204 } 205 206 // 6.4.3.2 (2016/02/19) (通常try-with-resources文によって)抑制された例外も出力します。 207 // このThrowable は、原因の Throwable は、求めません。 208 for( final Throwable supTh : th.getSuppressed() ) { 209 C_BUF.append( "Suppressed : " , supTh.getClass().getCanonicalName() ) // クラス名 210 .append( " " , supTh.getLocalizedMessage() ); // メッセージ 211 } 212 } 213 214// return buf.toString(); 215 // return buf.toString().trim(); 216 return C_BUF.toThrowMsg().trim(); 217 218// final Throwable cause = th == null ? new Throwable() : th.getCause(); // 原因の Throwable 219// final Throwable tmpTh = cause == null ? new Throwable() : cause; // 行番号取得のため、例外を発生させる。 220// 221// final CaseBuilder buf = new CaseBuilder() 222// .append( "Version: " , BuildNumber.ENGINE_INFO ) // 6.5.0.1 (2016/10/21) エンジンのバージョン 223// // Throwable.toString() で、クラス名とメッセージを分けて、それぞれを重複チェックする。 224// .append( "Error : " , tmpTh.getClass().getCanonicalName() ) // クラス名 225// .append( " " , tmpTh.getLocalizedMessage() ) // メッセージ 226// .append( "Message: " , msg ) // 追加メッセージ 227// .addStackTrace( tmpTh , MIN_STACK_SIZE , MIN_STACK_SIZE ); 228// 229// return buf.toString(); 230 } 231 232// /** 233// * このクラスが連続で呼ばれた場合のメッセージを返します。 234// * 235// * この、staticクラスは、色々な箇所で呼ばれる可能性があり、しかも、 236// * 一連のエラーで、別々に呼ばれると、メッセージが分断されます。 237// * 238// * そこで、暫定的に、連続にメッセージのみ、内部変数に設定していきます。 239// * ただし、同時に異なるエラーで呼ばれた場合には、それらのメッセージが 240// * 混在する(まざる)ので、暫定的な処置です。 241// * 242// * この呼び出しで、内部変数をクリアします。 243// * 244// * @og.rev 6.9.2.1 (2018/03/12) 連続で呼ばれた場合のメッセージを返す。 245// * 246// * @return 連続で呼ばれた場合のメッセージ 247// */ 248// public static String getLastMsg() { 249// final String rtn = buf.toString(); 250// buf.clear(); 251// 252// return rtn; 253// } 254 255 /** 256 * Throwable の getStackTrace() 結果の内、opengion に関する箇所だけのStackTraceElement配列を選別して返します。 257 * 258 * 通常、スタックトレース情報は、膨大なメッセージが含まれるため、その中の、org.opengion か、org.apache.jsp.jsp を 259 * 含む箇所だけを、抜粋します。 260 * ただし、ThrowUtilクラス(このクラス)内で、スタックトレースを new しているため、このクラスで発生した 261 * スタックトレースは、含まないようにしています。このクラスからエラーが発生しないことを望みます。 262 * 処理は、先頭から、minCnt件数までは、そのまま残し、それ以降は、関連するトレース情報のみ残します。 263 * 264 * @og.rev 6.9.2.1 (2018/03/12) 選別だけを別に用意します。 265 * 266 * @param th 元のThrowableオブジェクト(!= null 保障済み) 267 * @param minCnt StackTraceElementを登録する最小件数 268 * @return 選別されたStackTraceElement配列 269 * @see java.lang.Throwable#getStackTrace() 270 */ 271 public static StackTraceElement[] selectElement( final Throwable th , final int minCnt ) { 272// final StackTraceElement NULL_ELEMENT = new StackTraceElement( "","","",-1 ); 273 final Set<String> cacheSet = new HashSet<>(); // 同一スタックの除外用 274 275 final List<StackTraceElement> list = new ArrayList<>(); 276 277 int idx = 0; 278 for( final StackTraceElement stEle : th.getStackTrace() ) { 279 final String stkMsg = stEle.toString(); 280 if( cacheSet.contains( stkMsg ) ) { continue; } // 同じメッセージを出さない対応 281 cacheSet.add( stkMsg ); 282 283 final String cls = stEle.getClassName(); 284 285 boolean flag = true; // 連続で、出力しない。 286 if( minCnt < 0 || idx < minCnt || 287 // !cls.contains( "ThrowUtil" ) && // ここで、new Throwable しないので、判定不要。 288 cls.contains( "org.opengion" ) || cls.contains( "org.apache.jsp.jsp" ) ) { 289 list.add( stEle ); 290 flag = true; // 省略解除 291 } 292 else { 293 if( flag ) { 294// list.add( NULL_ELEMENT ); // StackTraceElementの省略 295 list.add( NULL_STE ); // StackTraceElementの省略 296 flag = false; // 連続で、出力しない。 297 } 298 } 299 idx++ ; 300 } 301 return list.toArray( new StackTraceElement[list.size()] ); 302 } 303 304 /** 305 * StringBuilder を、例外処理のスタックに特化した形で作り直した内部クラスです。 306 * 307 * printStackTrace() すると、膨大なメッセージが表示されるため、その中の、"org.opengion" と 308 * "org.apache.jsp.jsp" を含む箇所だけを、抜粋します。 309 * また、同じ内容のエラーも除外します。 310 * 311 * ※ 怪しい実装 312 * StackTrace は、内部的に、色々な箇所で呼ばれたり、同じ要因で、何度も再作成されたりします。 313 * この内部クラスも、ひとつの例外で、何度も作成されるため、重複チェックの方法を、時間制限で、 314 * 同一メッセージの重複処理を行っています。 315 * よって、まったく異なる要因のエラーが同時に発生した場合、重複処理の判定で、除外される可能性が 316 * あります。(発生場所の行番号が異なれば、重複処理されても残るので、デバッグ可能です) 317 * 318 * @og.rev 6.4.3.2 (2016/02/19) 新規追加 319 * @og.rev 6.9.2.1 (2018/03/12) 重複処理を、staticではなく、自身のオブジェクト内だけに変更します。 320 * @og.rev 6.9.9.1 (2018/08/27) StringBuilder を、List に変更したが、empty時の処理漏れ対応。 321 */ 322 private static final class CaseBuilder { 323 private static final String USE_KEY = "USE_KEY" ; 324 private static final long CACHE_TIME = 3000L; // Exceptionが発生した場合、連続してCallされるため、一まとめにする。 325 326// private static final ConcurrentMap<String,String> MSG_MAP = new ConcurrentHashMap<>(); // 同期Setの代わり。重複の取り除き判定 327 private final ConcurrentMap<String,String> MSG_MAP = new ConcurrentHashMap<>(); // 同期Setの代わり。重複の取り除き判定 328// private static volatile long lastCall = 0L; 329 private volatile long lastCall ; // 初期値 0L 330 331// private final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 332 private final List<String> list = new ArrayList<>(); 333 334 /** 335 * デフォルトコンストラクタ。 336 * 337 * 時間制限が過ぎれば、キャッシュをクリアします。 338 * 339 * @og.rev 6.4.3.2 (2016/02/19) 新規追加 340 * @og.rev 6.4.3.3 (2016/03/04) synchronized を取り除きます。 341 * @og.rev 6.9.2.1 (2018/03/12) 重複処理を、staticではなく、自身のオブジェクト内だけに変更します。 342 * @og.rev 6.9.9.1 (2018/08/27) デフォルトコンストラクタに、super(); を呼び出すようにします。 343 */ 344 public CaseBuilder() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 345// final long now = System.currentTimeMillis(); 346// if( now - lastCall > CACHE_TIME ) { // 前回キャッシュ時からの経過時刻が、CACHE_TIME を上回っている場合。 347// lastCall = now; 348// MSG_MAP.clear(); 349// } 350// } 351 352 /** 353 * 初期化します。 354 * 355 * @og.rev 6.9.2.1 (2018/03/12) 新規追加 356 * 357 * @return 自分自身 358 */ 359 public CaseBuilder init() { 360 final long now = System.currentTimeMillis(); 361 if( now - lastCall > CACHE_TIME ) { // 前回キャッシュ時からの経過時刻が、CACHE_TIME を上回っている場合。 362 lastCall = now; 363 MSG_MAP.clear(); 364// buf.setLength( 0 ); 365 list.clear(); 366 } 367 return this; 368 } 369 370 /** 371 * タイトルとメッセージを内部のStringBuilderに追記していきます。 372 * 373 * メッセージが、null や、空文字の場合は、何もしません。また、同一メッセージの追加は出来ません。 374 * 戻り値に、自分自身のオブジェクトを返すので、StringBuilder と同様に、接続できます。 375 * 376 * @og.rev 6.4.3.2 (2016/02/19) 新規追加 377 * @og.rev 6.4.3.3 (2016/03/04) 同一メッセージの判定を、trim() したキーで行います。 378 * @og.rev 6.9.2.1 (2018/03/12) タイトルがnullや空文字の場合も、なにもしません。 379 * 380 * @param title タイトルに相当します。 381 * @param msg メッセージ 382 * @return 自分自身 383 */ 384 public CaseBuilder append( final String title , final String msg ) { 385// if( msg != null && !msg.isEmpty() ) { 386 if( title != null && !title.isEmpty() && msg != null && !msg.isEmpty() ) { 387 // 超特殊処理1 388 // msg に改行コードを含む場合、最初の改行で、前後に分けて、それぞれをキャッシュ判定します。 389 // SQL文など、行が多く出る場合に、何度も繰り返されるのを避けるためです。 390 // 通常、1行目は、Exception発生元のため、異なるケースがありますが、2行目以降は、 391 // 同じケースが多いための処置です。 392 final String msg0 = msg.trim(); 393 394 // Map#putIfAbsent : 戻り値は、以前の値。追加有り、置換なし(先勝)、削除なし 395 // Map#put と何が違うかというと、置き換えが無い。速度は誤差範囲です。 396 if( MSG_MAP.putIfAbsent( msg0,USE_KEY ) == null ) { // 同期Setの代わり。未登録時は、null が戻る。 397 final int adrs = msg0.indexOf( '\n' ); // よくない判定方法 398 if( adrs < 0 ) { 399// buf.append( CR ).append( title ).append( msg0 ); 400 list.add( title + msg0 ); 401 } 402 else { 403 final String msg1 = msg0.substring( 0,adrs ).trim(); // 最初の改行で、前後に分割します。 404 final String msg2 = msg0.substring( adrs+1 ).trim(); 405 if( MSG_MAP.putIfAbsent( msg1,USE_KEY ) == null ) { 406// buf.append( CR ).append( title ).append( msg1 ); 407 list.add( title + msg1 ); 408 } 409 if( MSG_MAP.putIfAbsent( msg2,USE_KEY ) == null ) { 410// buf.append( CR ).append( title ).append( msg2 ); 411 list.add( title + msg2 ); 412 } 413 } 414 } 415 } 416 return this; 417 } 418 419 /** 420 * Throwable の getStackTrace() 結果の内、opengion に関する箇所だけのStackTraceElement配列をCaseBuilderオブジェクトに書き込みます。 421 * 422 * 通常、スタックトレース情報は、膨大なメッセージが含まれるため、その中の、org.opengion か、org.apache.jsp.jsp を 423 * 含む箇所だけを、抜粋します。 424 * ただし、ThrowUtilクラス(このクラス)内で、スタックトレースを new しているため、このクラスで発生した 425 * スタックトレースは、含まないようにしています。このクラスからエラーが発生しないことを望みます。 426 * 処理は、先頭から、MIN_STACK_SIZE 行は、元のままのメッセージを出力し、minCnt件数で、打ち切ります。 427 * minCnt が、0 か、マイナスの場合は、打ち切り制限なしです。( Integer.MAX_VALUE を指定させるのが嫌だっただけです。 ) 428 * 429 * @og.rev 6.4.2.0 (2016/01/29) 新規作成 430 * @og.rev 6.9.2.1 (2018/03/12) 選別だけを別に用意します。 431 * 432 * @param th 元のThrowableオブジェクト(!= null 保障済み) 433 * @param minCnt StackTraceElementを登録する最小件数 434 * @return 自分自身 435 * @see java.lang.Throwable#getStackTrace() 436 */ 437// public CaseBuilder addStackTrace( final Throwable th , final int minCnt , final int minCnt ) { 438 public CaseBuilder addStackTrace( final Throwable th , final int minCnt ) { 439 for( final StackTraceElement stEle : selectElement( th,minCnt ) ) { 440 if( stEle == null || "".equals( stEle.getClassName() ) ) { 441 append( " at " , "...." ); // StackTraceElement が省略されている。 442 } 443 else { 444 append( " at " , stEle.toString() ); 445 } 446 } 447 return this; 448 449// int idx = 0; 450// for( final StackTraceElement stEle : th.getStackTrace() ) { 451// final String cls = stEle.getClassName(); 452// 453// boolean flag = true; // 連続で、出力しない。 454// if( minCnt < 0 || idx < minCnt || 455// !cls.contains( "ThrowUtil" ) && 456// ( cls.contains( "org.opengion" ) || cls.contains( "org.apache.jsp.jsp" ) ) ) { 457// append( " at " , stEle.toString() ); 458// flag = true; // 省略解除 459// } 460// else { 461// if( flag ) { 462// append( " at " , "...." ); // 連続で、出力しない。 463// flag = false; 464// } 465// } 466// idx++ ; 467// 468// // // 6.9.2.1 (2018/03/12) 最小件数のbreak判定の方法を見直します。 469// // // ThrowUtil クラスは除外し、org.opengion か、org.apache.jsp.jsp のみ収集する。 470// // if( idx < minCnt || 471// // !cls.contains( "ThrowUtil" ) && 472// // ( cls.contains( "org.opengion" ) || cls.contains( "org.apache.jsp.jsp" ) ) ) { 473// // append( " at " , stEle.toString() ); 474// // } 475// // else { 476// // append( " at " , "...." ); // 最初の1回しか、出力されません。 477// // } 478// // if( minCnt > 0 && idx >= minCnt ) { break; } // minCnt 件で、処理を打ち切ります。 479// // idx++ ; 480// } 481// return this; 482 } 483 484 /** 485 * 内部のStringBuilderを、文字列に変換して返します。 486 * 487 * 出力の直前に改行コードを出しています。 488 * 489 * @og.rev 6.4.3.2 (2016/02/19) 新規追加 490 * @og.rev 6.9.9.1 (2018/08/27) StringBuilder を、List に変更したが、empty時の処理漏れ対応。 491 * 492 * @return 内部のStringBuilderの文字列化されたもの 493 */ 494 @Override 495 public String toString() { 496 if( list.isEmpty() ) { return CR; } // 6.9.9.1 (2018/08/27) 497 498// return buf.append( CR ).toString(); 499// return buf.toString().trim(); 500 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 501 for( final String msg : list ) { 502 buf.append( CR ).append( msg ); 503 } 504 return buf.toString(); 505 } 506 507 /** 508 * 内部のStringBuilderを、文字列に変換して返します。 509 * 510 * 出力の直前に改行コードを出しています。 511 * 512 * @og.rev 6.4.3.2 (2016/02/19) 新規追加 513 * @og.rev 6.9.9.1 (2018/08/27) StringBuilder を、List に変更したが、empty時の処理漏れ対応。 514 * 515 * @return 内部のStringBuilderの文字列化されたもの 516 */ 517 public String toThrowMsg() { 518 if( list.isEmpty() ) { return CR; } // 6.9.9.1 (2018/08/27) 519 520 final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE ); 521 for( final String msg : list ) { 522 if( ! msg.startsWith( " at " ) ) { 523 buf.append( CR ).append( msg ); 524 } 525 } 526 return buf.toString(); 527 } 528 } 529}