Java代码库的自动“修复”只有通用的`catch(Exception e)`

时间:2012-03-28 20:16:34

标签: java exception-handling automated-refactoring

我有一个很大的代码库,它有很多很多

的实例
try {
   // attempt to do something important
} catch (Exception e) {
   // do something lame
}

反模式。大约700个实例。我想知道是否有一个工具(例如,IDE或其他东西)可以神奇地,大量地用下一层专门的catch块替换所有这些东西。以下面显示的方式应用类似于IntelliJ或Eclipse "wrap with try/catch"的质量重构的东西。注意:我并不是说所有700都是已知IOException s;这只是一个例子,假设在特定情况下抛出的唯一异常类型是IOException)。

我正在寻求的重构是对IntelliJ / Eclipse提供的try{}块进行相同的语义分析,它提供了“wrap with catch”或“add to throws clause”快速修复:< / p>

try {
   // attempt to do something important
   // where an IOException is thrown
} catch (IOException e) {
   // still do something lame
}

据我所知,这并没有“解决”这个问题,但它保存了考古学的逐步手册。

想法?

detecting general exception catch antipattern上的相关问题。

2 个答案:

答案 0 :(得分:2)

我不认为有任何工具可以做你正在尝试的事情。我可以考虑使用以下算法,但在脚本中自动化它可能需要一些时间......甚至可能需要花费相同的时间来编写脚本来手动进行更改。

  1. 定义新例外
  2. class NeverThrown extends RuntimeException {}

    1. 全局替换catch (Exception e)catch (NeverThrown e)

    2. 编译所有文件

    3. 对于unreported exception .... must be caught...的每次出现,都会识别该例外,如果尚未添加,则将其添加到下一个catch块,例如将catch (NeverThrown e)替换为catch (NeverThrown, IOException e)

    4. 删除所有NeverThrown,并删除类定义。

    5. 当然,更大的智力工作在于决定做什么而不是什么跛脚&#34;。您将无法批量进行,每个案例都必须单独检查。如果我是你,我会停在第3步并经历错误,试图找出如何处理报告的每个未捕获的异常。

      或者您可以完全拒绝已检查的异常并删除所有try和catch块,在每个方法后添加throws Exception:)

答案 1 :(得分:2)

鉴于问题是:

查找表单的所有块:

 try { ... }
 catch (Exception e) { ... }

 try { ... }
 catch ( T1 e ) { ... }
 ....
 catch ( Tn e ) { ... }

对于所有T1,...这是一个可以进行代码更改的程序转换系统,以及抛出异常的原因,似乎是一个解决方案。

我们的DMS Software Reengineering Toolkit及其Java Front End可能会这样做。

您需要一个可以计算从主块内部抛出的异常集的分析器。您可能还希望根据对象层次结构对这些异常进行分类;如果Tm是Tn的特化,您可能希望为嵌套尝试生成Tm和Tn的处理程序。 DMS具有完整的类型分析,因此它可以确定代码中的类型,并由代码块抛出。人们必须编写自定义DMS代码来计算异常的对象层次结构。

您需要一个调用图,因此可以将调用图中找到的异常传播到try站点。我们有这个,但它需要Java 1.7的一些工作。

您需要转换应用程序,修改代码。我认为你需要担心链接捕获来处理一般情况。使用DMS,它应该看起来像:

rule specialize_catch(b_try: block,
      E: qualifed_identifer, e: IDENTIFIER, b_recover: block,
      c_pre: catches, c_post: catches):
   statement -> statement
 " try { \b_try } 
   \c_pre
   catch ( \E \e ) { \b_recover }
   \c_post "
 -> 
  " try { \b_try }
    \c_pre 
    catch ( \least_specialized\(\E\,\b_try\,\c_pre\) \e ) { \b_recover }
    catch ( \E e ) { \b_recover }
    \c_post "
    if exists_specialized_exception(E,b_try,c_pre);

要转换的语法是* meta * quotes“...”中的代码,以便将其与重写规则的语法分开。重写规则有许多部分。它指定一个名称(我们通常有数百个)。它提供了一组命名占位符(b_try,E,b_recover,...),它们表示目标语言(在本例中为Java)中的特定的,命名的语法形式,并以metaquote和转义(反向)形式之外的裸形式编写在metaquotes里面。 c_pre是一系列catch结构的名称;我们可以这样做,因为“catch”在抽象中形成一个关联列表,类似于c_post。它提供了元函数调用(例如,least_specialized,exists_specialized_exception),它可以调用自定义DMS机器来计算结果(布尔值或新语法[树])。你会注意到对@subspecialized的元函数调用甚至具有元函数调用的语法转义(例如,逗号和括号),因为它们不是Java语言的一部分;在Java代码之外,这样的元函数调用不需要转义。最重要的是,它有一个左侧(“匹配此”,绑定变量)和右侧(如果规则条件为真,则“替换为此”。

元函数least_specialized和exists_specialized将计算,对于主代码块b_try可能抛出的异常,以及由现有捕获c_pre处理的异常,以及当前异常类型E,c_pre之上和E之下的最常见异常,以及插入一个新的catch块。如果不存在,则if失败并且不再进行异常插入。您可能需要添加单个转换来对重复的b_recover块进行解除克隆。

我显然没有实现这一点,可能没有完全考虑过。但我可以将其视为可能解决方案的途径。 YMMV。

我要说700个实例,用DMS做这个可能是非常有限的。如果你个人花了10分钟(编辑,编译,哎呀...)这是7000分钟或~~ 100小时,大约2周。我怀疑你可以配置DMS来快速完成这项工作,特别是以前从未这样做过。 (我公司有专家的DMS用户,这可能是一个可行的时间框架。)

但声称可能存在一种工具。