2015-09-15 2 views
4

У нас есть огромный проект, в котором многие методы были объявлены заранее, а реализации выполняются. Все объявленные методы имеют тело, которое просто выдает исключение, скажем, UnimplException. Теперь, когда методы были объявлены, и было предоставлено действительное (компилируемое) тело, их можно вызвать из других методов.Список всех нереализованных методов, вызванных методом

Теперь вопрос заключается в том, есть ли способ перечислить все такие нереализованные (имеющие только компилируемое тело, бросающие конкретное исключение) методы, заданные определенным методом?

Для иллюстрации более (код, чтобы передать идею, а не строго компилятор дружественных):

class A { 
    methA() { 
     throw new UnimplException(); 
    } 
} 

class B { 
    methB() { 
     // proper body 
     // and calls methA 
     A.methA(); 
     // does something else 
     // and returns. 
    } 
} 

class C { 
    methC() { 
     // proper body 
     // calls methB 
     B.methB(); 
    } 
} 

Таким образом, если мы будем исходить из, скажем, methC, то мы хотим поехать весь путь вниз по дерево методов для достижения мета-метана, потому что methC называет methB (который правильно реализован, и мы не заинтересованы), который, в свою очередь, вызывает methA, который не выполняется должным образом, и это то, что мы хотим найти. Мы хотим найти все такие нереализованные методы, начиная с метода и пройдя несколько уровней до тех пор, пока не охватим все такие нереализованные методы.

Мы думали о JavaAssist, но мы не знаем, как спуститься со всех уровней, потому что он, кажется, дает нам все методы, вызванные методом, но не рекурсивно.

Любая помощь очень ценится :)

+2

Использует grep вариант? – Fildor

+0

Это даже не компилируется. У вас не может быть 'throws' в теле, это должно быть' throw new UnimplException() 'и поместить' throws UnimplException' сразу после 'methA()'. 'methA()' и 'methB()' также не являются статичными, поэтому вы не можете их так называть. –

+0

Из кода, который вы опубликовали, попытка компиляции сделает флаг java-компилятора для каждого нереализованного метода, потому что они бросают исключение, не сообщая об этом (или даже бросая его должным образом, вам нужно новое ключевое слово и 'UnimplException()') –

ответ

2

Вы видели этот проект: https://github.com/gousiosg/java-callgraph? Это, похоже, делает часть интроспекции Java, перечисляя каждый вызов метода из каждого метода в файле jar. Я бы попытался использовать это, чтобы сделать тяжелый подъем синтаксического анализа вашего кода, а затем просто повторить результаты.

Что-то вроде:

  1. Используйте код, чтобы построить граф вызовов список всех вызовов методов.
  2. Сохраните эти данные где-нибудь.
  3. Рекурсивно разобрать эту структуру, чтобы найти соответствующие методы.

Так из вашего примера, шаг 1 будет давать что-то вроде следующего:

A:methA -> UnimplException:<init> 
B:methB -> A:methA 
C:methC -> B:methB 

Тогда засунуть тех, кто в Multimap и сделать довольно простой рекурсивный поиск:

// this is populated from the output of the callgraph code 
com.google.common.collect.Multimap<String, String> methodMap; 

void checkAllMethods() { 
    for (String method : methodMap.keySet()) { 
    List<String> callStack = new ArrayList<>(); 
    if (doesMethodThrowUnimplException(method, callStack)) { 
     System.out.println(method); 
     // can print callStack too if interested 
    } 
    } 
} 

boolean doesMethodThrowUnimplException(String method, List<String> callStack) { 
    for (String child : methodMap.get(method)) { 
    // have to check the exact method name from callgraph 
    if (child.equals("UnimplException:<init>")) { 
     return true; 
    } 
    // recurse into child if not already seen 
    if (!callStack.contains(child)) { 
     callStack.add(child); 
     if (doesMethodThrowUnimplException(child, callStack)) { 
     return true; 
     } 
     callStack.remove(callStack.size() - 1); 
    } 
    } 
    return false; 
} 

Безразлично» t строго соответствует вашим требованиям, так как это сообщит о любом методе, который выдает UnimplException, а не тех, кто только генерирует исключение, но не уверен, что это важно.

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

+0

благодарит @ Барни! Я попробую это ... идея звучит хорошо. :) – popeye

+0

@popeye не беспокоится - надеюсь, что это поможет. Просто попробовал материал для кодографа, и быстрый взгляд, похоже, работает очень хорошо. Также просто обновил рекурсивный код - предыдущая версия завершилась неудачей, если бы цикл кода был обнаружен перед вызовом метода исключения. – Barney

Смежные вопросы