Автоматическое «исправление» для кодовой базы Java с использованием только общего «catch (Exception e)» - PullRequest
1 голос
/ 29 марта 2012

У меня есть большая кодовая база, у которой есть много-много экземпляров

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

антипаттерны. Примерно 700 экземпляров. Мне интересно, есть ли инструмент (например, IDE или что-то), который мог бы волшебным образом и по массе заменить все эти вещи следующим уровнем специализированных блоков захвата. То, что применило бы массовый рефакторинг, похожий на "обертывание с try / catch" IntelliJ или Eclipse , как показано ниже. ПРИМЕЧАНИЕ: я не говорю, что все 700 известны IOException с; это всего лишь пример, предполагающий, что единственным типом исключения, выдаваемым в конкретном случае, был IOException).

Рефакторинг, который я ищу, - это то, что выполняет тот же семантический анализ блока try{}, что и IntelliJ / Eclipse, чтобы обеспечить быстрые исправления для "wrap with catch" или "add to throws:"

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

Я понимаю, что это не "решает" проблему, но экономит пошаговую ручную археологию.

Идеи

Смежный вопрос по обнаружению общего исключения catch antipattern .

Ответы [ 2 ]

2 голосов
/ 29 марта 2012

Учитывая, что проблема:

Найти все блоки вида:

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

с

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

для всех T1, ... Таким образом, система преобразования программ, которая может вносить изменения в код и рассуждать об исключениях, выглядит как решение.

Наш инструментарий реинжиниринга программного обеспечения DMS с интерфейсом Java вполне может это сделать.

Вам нужен анализатор, который может вычислить набор исключений, генерируемых из основного блока. Вы, вероятно, хотите классифицировать эти исключения в соответствии с иерархией объектов; если Tm является специализацией Tn, вы можете сгенерировать обработчик для Tm и Tn в качестве вложенных попыток. DMS имеет полный анализ типов, поэтому он может определять типы в коде и генерировать их блоком кода. Нужно было бы написать собственный код DMS для вычисления иерархии объектов для исключений.

Вам нужен граф вызовов, чтобы можно было распространить исключения, найденные в графе вызовов, на пробный сайт. У нас это есть, но для 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);

Синтаксис для преобразования - это код в * мета * кавычках "...", чтобы отделить его от синтаксиса правил перезаписи. Правило перезаписи состоит из нескольких частей. Это указывает имя (у нас часто есть сотни). Он предоставляет набор именованных заполнителей (b_try, E, b_recover, ...), представляющих конкретные именованные синтаксические формы на целевом языке (в данном случае Java) и записанные в голой форме вне мета-цитаты и экранированной (с обратной косой чертой) формы внутри мета-кавычек. c_pre - это имя серии конструкций catch; мы можем сделать это, потому что «ловит» формирует ассоциативный список в аннотации, и аналогично для c_post. Он предусматривает вызовы мета-функций (например, наименьшей_специализированной, существует_специализированной_эксклюзии), которые могут вызывать пользовательские механизмы DMS для вычисления результатов (логические значения или новый синтаксис [деревья]). Вы заметите, что вызов метафункции для less_specialized даже содержит синтаксис экранированного вызова метафункции (например, запятые и скобки), поскольку они не являются частью языка Java; вне Java-кода такие вызовы метафункций не нужно экранировать. И самое главное, он имеет левую часть («сопоставить это», связывая метавариабельные переменные) и правую часть («заменить на это», если условие правила истинно.

Метафункции less_specialized и exist_specialized вычисляют для исключений, которые может генерировать основной кодовый блок b_try, и тех, которые обрабатываются существующими уловами c_pre и текущим типом исключения E, наиболее общим исключением выше c_pre и ниже E, и новый блок захвата вставлен. Если ничего не существует, происходит сбой if и больше не производится вставка исключений. Возможно, вам понадобятся дополнительные преобразования для клонирования дублированного блока b_recover.

Я, очевидно, не реализовал это и, возможно, не продумал это полностью. Но я вижу в этом путь к возможному решению. YMMV.

Я скажу, что для 700 случаев это, вероятно, довольно незначительно, делать это с DMS. Если лично вам потребовалось 10 минут (редактировать, компилировать, упс ...), это 7000 минут или ~ 100 часов, около 2 недель. Я сомневаюсь, что вы могли бы настроить DMS, чтобы сделать это так быстро, особенно никогда раньше. (У меня есть опытные пользователи DMS в моей компании, для которых это, вероятно, приемлемый период времени).

Но утверждается, что инструмент, скорее всего, существует.

2 голосов
/ 29 марта 2012

Я не думаю, что существуют какие-либо инструменты, чтобы делать то, что вы пытаетесь.Я могу подумать о следующем алгоритме, но автоматизация его в сценарии может занять некоторое время ... для написания сценария может потребоваться даже столько времени, сколько потребуется для внесения изменений вручную.

  1. Определитьновое исключение

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, и удалите определение класса.

Конечно, большие интеллектуальные усилия заключаются в определении того, что делать вместо «чего-то»ламе".То, что вы не сможете сделать оптом, каждый случай должен быть проверен индивидуально.Если бы я был вами, я бы остановился на шаге № 3 и рассмотрел ошибки, пытаясь выяснить, как обрабатывать каждое необработанное исключение, о котором сообщалось.

Или вы можете полностью осудить отмеченные исключения и удалить все блоки try и catch, добавив throws Exception после каждого метода:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...