詳細
前提として該当システムではcatchブロックで補足した例外を
MyExceptionという独自定義の例外に詰めなおしてthrowする規約になっているとする。
サンプルコード
サンプルコード1(sample1.java〜sample3.java)
catchブロック2件正常、2件異常のサンプル
package catchsample; public class SampleCatch { public static void main(String[] args) throws MyException { try { System.out.println("hoge"); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (NullPointerException e) { if (e.getMessage() == null) { System.out.println("null"); } } catch (IllegalAccessError e) { throw new MyException(); } catch (Exception e) { if (e.getMessage() == null) { System.out.println("null"); } throw new MyException(); } } }
サンプルコード2(sample4.java)
catchブロックなしのサンプル
package catchsample; public class SampleCatch { public static void main(String[] args) throws MyException { System.out.println("hoge"); } }
サンプルディレクトリ構成
C:. │ sample1.java │ sample2.java │ sample3.java │ sample4.java │ ├─dir1 │ │ sample1.java │ │ sample2.java │ │ sample3.java │ │ sample4.java │ │ │ └─dir1_1 │ sample1.java │ sample2.java │ sample3.java │ sample4.java │ └─dir2 │ sample1.java │ sample2.java │ sample3.java │ sample4.java │ └─dir2_1 sample1.java sample2.java sample3.java sample4.java
チェック処理本体
exception_checker.rb
# encoding: UTF-8 require 'Set' require "find" # # Javaのcatch句でMyExceptionを投げていない個所を検出する # # author:tbpg # create:2013/04/14 # class ExceptionChecker # 調査対象から除外する名称リスト # TODO 設定ファイルに逃がすように修正したほうが良い EXCLUDES = ["dir2_1","sample3.java"] # 出力CSVのヘッダー HEADER = "java_file_path,line_no,source" # Javaのクラス名 JAVA_FILE_NAME = /.*\.java/ # 行区切り文字 LINE_SEPARATOR = "\n" # catch句に必要な処理 CATCH_REQUIRED_CODE = /\sthrow\snew\sMyException\(\)/ # 中括弧開き OPEN_BRACE = "{" # 中括弧閉じ CLOSE_BRACE = "}" def output_illegal_catch_blocks(target_path) output_header Find.find(target_path).each do |file| next unless FileTest.file? file next unless java_sorce_file? file next if exclude? file src = File.open(file).read next unless has_catch? src each_lines = src.split(LINE_SEPARATOR) illegal_catch_blocks = get_illegal_catch_blocks(each_lines) output_illegal_catch(file, illegal_catch_blocks) end end private def output_header puts HEADER end def java_sorce_file?(file) file =~ JAVA_FILE_NAME end def exclude?(file_name) ExceptionChecker::EXCLUDES.each {|v|return true if file_name.include? v} return true if file_name.include? "Test.java" return false end def has_catch?(src) src =~ /\}\s*catch\s*\(/ end def get_illegal_catch_blocks(each_lines) illegal_catch_lines = [] each_lines.each_with_index do |line,i| next unless line.include? "catch" catch_line = i + 1 search_lines = each_lines[catch_line..each_lines.size] illegal_catch_lines << ",#{catch_line.to_s},#{line}" unless valid_catch?(search_lines) end illegal_catch_lines end def valid_catch?(search_lines) start_brace_count = 0 search_lines.each do |line| return true if has_myexcepton?(line) if has_close_brace?(line) return false if close_catch_block?(start_brace_count) start_brace_count -= 1 next end if has_open_brace?(line) start_brace_count += 1 next end end false end def has_myexcepton?(line) line =~ CATCH_REQUIRED_CODE end def has_close_brace?(line) line.include? CLOSE_BRACE end def has_open_brace?(line) line.include? OPEN_BRACE end def close_catch_block?(start_brace_count) start_brace_count == 0 end def output_illegal_catch(file, illegal_catch_blocks) illegal_catch_blocks.each {|line|puts file + line} if illegal_catch_blocks.size > 0 end end
チェック処理呼び出しコード
exception_checker_executor.rb
# encoding: UTF-8 require "./exception_checker" if ARGV.size != 1 STDERR.puts "パラメータに調査対象のフルパスを指定してください" exit end ExceptionChecker.new.output_illegal_catch_blocks ARGV[0]
チェック実行用コマンド
$ruby exception_checker_executor.rb "C:/XXXX/test_project/" > output.txt
結果
CSV形式の出力結果
java_file_path,line_no,source C:/XXXX/test_project/dir1/dir1_1/sample1.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/dir1/dir1_1/sample1.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/dir1/dir1_1/sample2.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/dir1/dir1_1/sample2.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/dir1/sample1.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/dir1/sample1.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/dir1/sample2.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/dir1/sample2.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/dir2/sample1.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/dir2/sample1.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/dir2/sample2.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/dir2/sample2.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/sample1.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/sample1.java,9, } catch (NullPointerException e) { C:/XXXX/test_project/sample2.java,7, } catch (IllegalArgumentException e) { C:/XXXX/test_project/sample2.java,9, } catch (NullPointerException e) {