Регистрация  |  Вход

Неиспользуемые методы

Добрый День!

Необходимо найти неиспользуемые методы в довольно большом объёме кода. Я уже создавал тему, которая относится к этой. Спасибо wilder за полезную ссылку.
Но но основную задачу мне так пока и не удалось решить. С самого начала я попробовал запустить приложение по ссылке в блоге однако возникает проблема, которая описана внизу, в последних комментариях.

Пробовал найти что-то похожее в открытом доступе, тоже ничего нет. Единственное, что нашёл вот этот плагин, который ищет неиспользуемые private методы, но это, к сожалению, капля в море.

По ссылке в блоге поиск методов происходит с помощью Tooling API. Дело в том, что там есть замечательный объект Symbol Table, который хранит в себе внешние ссылки externalReferences-->methods на вызываемые в данном классе методы, а также локальные methods-->references. Но я совсем новичок и хорошо разобраться с использованием Tooling API мне пока не удалось.

Далее я хотел написать на джаве парсер, с помощью регулярных выражений, которой бы сначала собирал по всем классам все методы, а затем искал их вызов по всем классам. И если методы я вроде находил исправно(хотя тоже были лишние и не учтённые ситуации), то найти вызов этих методов в других классах довольно затруднительно, так как метод класса можно вызвать очень по разному.

Далее мой взор снова обратился к Tooling API. Я нашёл обёртку для Tooling API, которая позволяет его использовать напрямую через apex. И пробовал похожим образом как здесь описано(SOAP) получить ссылки на вызов методов в других классах. Однако при получении symbol table все ссылки почему-то равны null.

Мб, кто сталкивался с проблемой поиска неиспользуемых методов? Буду рад любой помощи.

Добрый День!

Необходимо найти неиспользуемые методы в довольно большом объёме кода. Я уже создавал тему, которая относится к [url=https://salesforce-developer.ru/forum/topic-spisok-metodov-klassa]этой[/url]. Спасибо wilder за полезную ссылку.
Но но основную задачу мне так пока и не удалось решить. С самого начала я попробовал запустить приложение по ссылке [url=https://andyinthecloud.com/2013/02/02/spring-cleaning-apex-code-with-the-tooling-api/]в блоге[/url] однако возникает проблема, которая описана внизу, в последних комментариях. 

Пробовал найти что-то похожее в открытом доступе, тоже ничего [url=http://salesforce.stackexchange.com/questions/33903/how-can-i-find-unused-methods-and-variables]нет[/url]. Единственное, что нашёл [url=http://codescan.villagechief.com/eclipse/]вот этот плагин[/url], который ищет неиспользуемые private методы, но это, к сожалению, капля в море.

По ссылке в блоге поиск методов происходит с помощью Tooling API. Дело в том, что там есть замечательный объект [url=https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_symboltable.htm]Symbol Table[/url], который хранит в себе внешние ссылки externalReferences-->methods на вызываемые в данном классе методы, а также локальные methods-->references. Но я совсем новичок и хорошо разобраться с использованием Tooling API мне пока не удалось.

Далее я хотел написать на джаве парсер, с помощью регулярных выражений, которой бы сначала собирал по всем классам все методы, а затем искал их вызов по всем классам. И если методы я вроде находил исправно(хотя тоже были лишние и не учтённые ситуации), то найти вызов этих методов в других классах довольно затруднительно, так как метод класса можно вызвать очень по разному.

Далее мой взор снова обратился к Tooling API. Я нашёл [url=https://github.com/afawcett/apex-toolingapi]обёртку[/url] для Tooling API, которая позволяет его использовать напрямую через apex. И пробовал похожим образом как здесь [url=http://salesforce.stackexchange.com/questions/116165/symbol-table-from-apex-class]описано(SOAP)[/url] получить ссылки на вызов методов в других классах. Однако при получении symbol table все ссылки почему-то равны null.

Мб, кто сталкивался с проблемой поиска неиспользуемых методов? Буду рад любой помощи.





А прогнать тесты и посмотреть не тестируемый код не вариант?

А прогнать тесты и посмотреть не тестируемый код не вариант?

Если они есть :D

Если они есть :D

Построить дерево вызовов или воспользоваться IDE.

Построить дерево вызовов или воспользоваться IDE.

Andrii Muzychuk
А прогнать тесты и посмотреть не тестируемый код не вариант?

Не могли бы вы подробней объяснить, что имеете ввиду?)
Gres
Построить дерево вызовов или воспользоваться IDE.

А каким образом это сделать?

Дело в том, что SF я изучаю меньше 2 месяцев и, конечно, много чего просто не знаю.

[quote="Andrii Muzychuk"]А прогнать тесты и посмотреть не тестируемый код не вариант?[/quote]
Не могли бы вы подробней объяснить, что имеете ввиду?)
[quote="Gres"]Построить дерево вызовов или воспользоваться IDE.[/quote]
А каким образом это сделать?

Дело в том, что SF я изучаю меньше 2 месяцев и, конечно, много чего просто не знаю.

Только два месяца и такая задача. Я 4 года работаю и задач для которых надо Tooling API не было еще.

Только два месяца и такая задача. Я 4 года работаю и задач для которых надо Tooling API не было еще.

После того, как пройдут все тесты можно увидеть, какой код не тестируется. В моем случае не тестируется код в блоках catch (ну оооочень редко тестируется) или "лишние" проверки на null. Вся бизнес-логика обязательно под тестами. Если какой-то метод никак не используется бизнес-логикой, то он не будет покрыт тестами.

DevNull
Только два месяца и такая задача. Я 4 года работаю и задач для которых надо Tooling API не было еще.

Я 5. Но видел только __с и __r поля :-) И странички делаю на Visualforce почти без JavaScript и CSS, что уж говорить о JS фреймворках.

После того, как пройдут все тесты можно увидеть, какой код не тестируется. В моем случае не тестируется код в блоках catch (ну оооочень редко тестируется) или "лишние" проверки на null. Вся бизнес-логика обязательно под тестами. Если какой-то метод никак не используется бизнес-логикой, то он не будет покрыт тестами.

[quote="DevNull"]Только два месяца и такая задача. Я 4 года работаю и задач для которых надо Tooling API не было еще.[/quote]
Я 5. Но видел только __с и __r поля :-) И странички делаю на Visualforce почти без JavaScript и CSS, что уж говорить о JS фреймворках.

Andrii Muzychuk
После того, как пройдут все тесты можно увидеть, какой код не тестируется. В моем случае не тестируется код в блоках catch (ну оооочень редко тестируется) или "лишние" проверки на null. Вся бизнес-логика обязательно под тестами. Если какой-то метод никак не используется бизнес-логикой, то он не будет покрыт тестами.

Почему? Если допустим под код, который использовался, писался тест, а потом код перестал использоваться?(или я что-то не понимаю)

+использование кода более 80%, т.е. посмотреть надо будет большие объёмы.

Мне сказали найти все неиспользуемые методы, а как их искать это уже мои проблемы

[quote="Andrii Muzychuk"]После того, как пройдут все тесты можно увидеть, какой код не тестируется. В моем случае не тестируется код в блоках catch (ну оооочень редко тестируется) или "лишние" проверки на null. Вся бизнес-логика обязательно под тестами. Если какой-то метод никак не используется бизнес-логикой, то он не будет покрыт тестами.[/quote]

Почему? Если допустим под код, который использовался, писался тест, а потом код перестал использоваться?(или я что-то не понимаю)

+использование кода более 80%, т.е. посмотреть надо будет большие объёмы.



Мне сказали найти все неиспользуемые методы, а как их искать это уже мои проблемы 

Если ты пишешь интеграционные тесты, то ты тестируешь варианты использования приложения.
Например, есть у тебя поле Скидка__с. Например, если ее заполняют, то поле КОплате__с вычисляется как Стоимость__с * Скидка__с / 100. И вот если этот метод, который вичисляет стоимость со скидкой не вызывается (убрали его из тригера), то сколько бы ты не заполнял поле Скидка__с, метод протестирован не будет. В Эклипсе тебе сразу этот метод подсветят красным.
Если же тупые юнит тесты, то да, мой метод не работает.

Если ты пишешь интеграционные тесты, то ты тестируешь варианты использования приложения.
Например, есть у тебя поле Скидка__с. Например, если ее заполняют, то поле КОплате__с вычисляется как Стоимость__с * Скидка__с / 100. И вот если этот метод, который вичисляет стоимость со скидкой не вызывается (убрали его из тригера), то сколько бы ты не заполнял поле Скидка__с, метод протестирован не будет. В Эклипсе тебе сразу этот метод подсветят красным.
Если же тупые юнит тесты, то да, мой метод не работает.

Andrii Muzychuk
Если ты пишешь интеграционные тесты,

Ну что вы все про идеальные случаи пишете?
Ну не бывает никогда нормальных тестов на проекте.
А используемые методы по ним вычислить точно не удастся.
Будьте пессимистами!
Пример - есть метод, для него есть тест. Метод не используется, но в тестах он покрыт. Это конечно не интеграционный тест - но какая хрен разница - тест то есть.

[quote="Andrii Muzychuk"]Если ты пишешь интеграционные тесты,[/quote]
Ну что вы все про идеальные случаи пишете?
Ну не бывает никогда нормальных тестов на проекте.
А используемые методы по ним вычислить точно не удастся. 
Будьте пессимистами!
Пример - есть метод, для него есть тест. Метод не используется, но в тестах он покрыт. Это конечно не интеграционный тест - но какая хрен разница - тест то есть.

Короче - не пудри мозг с SF - вытягивай весь проект и ищи тулы для java которые анализируют код - 99% что найдешь потому что apex это офигенский клон java. По другому никак.
На счет всяких Tooling API или IDE - устанешь делать. А если сделаешь можешь продавать как офигенный продукт.

Короче - не пудри мозг с SF - вытягивай весь проект и ищи тулы для java которые анализируют код - 99% что найдешь потому что apex это офигенский клон java. По другому никак.
На счет всяких Tooling API или IDE - устанешь делать. А если сделаешь можешь продавать как офигенный продукт.

Парни, все уже до вас сделали.

Парни, все уже до вас [url=http://salesforce.stackexchange.com/questions/33903/how-can-i-find-unused-methods-and-variables]сделали[/url].

Andrii Muzychuk
Парни, все уже до вас сделали.

Эта ссылка уже есть в моём посте сверху. Дело в том, что мне не удалось запустить данное приложение возникают ошибки, которые описаны в комментариях, и, к сожалению, пока нет решения не по одной из них.

[quote="Andrii Muzychuk"]Парни, все уже до вас [url=http://salesforce.stackexchange.com/questions/33903/how-can-i-find-unused-methods-and-variables]сделали[/url].[/quote]
Эта ссылка уже есть в моём посте сверху. Дело в том, что мне не удалось запустить данное приложение возникают ошибки, которые описаны в комментариях, и, к сожалению, пока нет решения не по одной из них.

Dmitry Shnyrev
Короче - не пудри мозг с SF - вытягивай весь проект и ищи тулы для java которые анализируют код - 99% что найдешь потому что apex это офигенский клон java. По другому никак.
На счет всяких Tooling API или IDE - устанешь делать. А если сделаешь можешь продавать как офигенный продукт.

Дело в том, что для джава это стандартные функции для IDE, т.е. Eclipse и IDEA сразу подсвечивает данные методы.

Я конечно проверю данное предположение, но всё таки есть такие существенные различия с java как case-insensitive синтаксис, что мне кажется может повлиять на работу таких тулов, если они вообще есть, так как это всё-такие стандартные вещи для IDE

[quote="Dmitry Shnyrev"]Короче - не пудри мозг с SF - вытягивай весь проект и ищи тулы для java которые анализируют код - 99% что найдешь потому что apex это офигенский клон java. По другому никак.
На счет всяких Tooling API или IDE - устанешь делать. А если сделаешь можешь продавать как офигенный продукт.[/quote]
Дело в том, что для джава это стандартные функции для IDE, т.е. Eclipse и IDEA сразу подсвечивает данные методы. 

Я конечно проверю данное предположение, но всё таки есть такие существенные различия с java как case-insensitive синтаксис, что мне кажется может повлиять на работу таких тулов, если они вообще есть, так как это всё-такие стандартные вещи для IDE

Не совсем понял почему у тебя не получается. Ссылки что приведены толковые и там доходчиво обяснено как нужно делать.

Возникает только вопрос с реализацией. Но и тут при желании можно разобраться.

В общем читай внимательно мою первую ссылку и делай по шагам. Там есть пару лимитов в которые ты скорее всего упрешься если будешь писать на апексе, на джаве этого нет. Так что выбирай сам.

Не совсем понял почему у тебя не получается. Ссылки что приведены толковые и там доходчиво обяснено как нужно делать. 

Возникает только вопрос с реализацией. Но и тут при желании можно разобраться.

В общем читай внимательно мою первую ссылку и делай по шагам. Там есть пару лимитов в которые ты скорее всего упрешься если будешь писать на апексе, на джаве этого нет. Так что выбирай сам.

Dmitry Shnyrev
На счет всяких Tooling API или IDE - устанешь делать.

1 кнопку нажать устанешь?

[quote="Dmitry Shnyrev"]На счет всяких Tooling API или IDE - устанешь делать.[/quote]
1 кнопку нажать устанешь?

Ага, пока найдешь какую нажать то устанешь.
Тут же никто не подскажет какую.

Ага, пока найдешь какую нажать то устанешь. 
Тут же никто не подскажет какую.

Dmitry Shnyrev
Ага, пока найдешь какую нажать то устанешь.
Тут же никто не подскажет какую.

А, ну да, ну да.
А вообще через tooling API все работает.

[quote="Dmitry Shnyrev"]Ага, пока найдешь какую нажать то устанешь.
Тут же никто не подскажет какую.[/quote]
А, ну да, ну да.
А вообще через tooling API все работает.

wilder
Не совсем понял почему у тебя не получается. Ссылки что приведены толковые и там доходчиво обяснено как нужно делать.

Возникает только вопрос с реализацией. Но и тут при желании можно разобраться.

В общем читай внимательно мою первую ссылку и делай по шагам. Там есть пару лимитов в которые ты скорее всего упрешься если будешь писать на апексе, на джаве этого нет. Так что выбирай сам.

Я немного капнул глубже, точнее разобрался почему у меня в последнем случае symbolTable = null. Дело в том, что я получал её через ApexClass, а так нельзя(The SymbolTable returned from ApexClass does not contain references; to retrieve a SymbolTable with references, use ApexClassMember.).
Затем автор обёртки ToolingAPI и того приложения в твоей ссылке, указал мне на данный проект, там как раз используется ApexClassMember и можно получить SymbolTable со всеми ссылками, что я и сделал. Я переписал там метод compile из UmlService для того, чтобы он создавал сразу все ApexClassMember. Однако как ты и предсказывал, я упираюсь в лимиты по callout. На каждый класс нужен один ApexClassMember, на один ApexClassMember уходит один callout. А классов у меня в несколько раз больше, чем 100 (Total number of callouts (HTTP requests or Web services calls) in a transaction) Т.о. получается, необходимо как-то в несколько заходов создавать ApexClassMembers? Или есть возможность это "красиво" обойти?

[quote="wilder"]Не совсем понял почему у тебя не получается. Ссылки что приведены толковые и там доходчиво обяснено как нужно делать. 

Возникает только вопрос с реализацией. Но и тут при желании можно разобраться.

В общем читай внимательно мою первую ссылку и делай по шагам. Там есть пару лимитов в которые ты скорее всего упрешься если будешь писать на апексе, на джаве этого нет. Так что выбирай сам.[/quote]

Я немного капнул глубже, точнее разобрался почему у меня в последнем случае symbolTable = null. Дело в том, что я получал её через ApexClass, а так нельзя([url=https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/tooling_api_objects_apexclass.htm]The SymbolTable returned from ApexClass does not contain references; to retrieve a SymbolTable with references, use ApexClassMember.[/url]). 
Затем автор обёртки ToolingAPI и того приложения в твоей ссылке, указал мне на  [url=https://github.com/afawcett/apex-umlcanvas]данный проект[/url], там как раз используется ApexClassMember и можно получить SymbolTable со всеми ссылками, что я и сделал. Я переписал там метод compile из [url=https://github.com/afawcett/apex-umlcanvas/blob/master/src/classes/UmlService.cls]UmlService[/url] для того, чтобы он создавал сразу все ApexClassMember. Однако как ты и предсказывал, я упираюсь в лимиты по callout. На каждый класс нужен один ApexClassMember, на один ApexClassMember уходит один callout. А классов у меня в несколько раз больше, чем 100 [url=https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_apexgov.htm](Total number of callouts (HTTP requests or Web services calls) in a transaction)[/url] Т.о. получается, необходимо как-то в несколько заходов создавать ApexClassMembers? Или есть возможность это "красиво" обойти?

Konstruktor
Т.о. получается, необходимо как-то в несколько заходов создавать ApexClassMembers? Или есть возможность это "красиво" обойти?

Есть. Но больше подробностей не будет.

[quote="Konstruktor"] Т.о. получается, необходимо как-то в несколько заходов создавать ApexClassMembers? Или есть возможность это "красиво" обойти?[/quote]

Есть. Но больше подробностей не будет.

Konstruktor
Или есть возможность это "красиво" обойти?

Делать тулу на на Apex, а на нормальном языке без лимитов.

[quote="Konstruktor"]Или есть возможность это "красиво" обойти?[/quote]
Делать тулу на на Apex, а на нормальном языке без лимитов.

Dmitry Shnyrev
Konstruktor
Или есть возможность это "красиво" обойти?

Делать тулу на на Apex, а на нормальном языке без лимитов.

Ну, а если всё-таки на Apex? Можно ли как-то сериализовать по очереди все объекты в один JSONGenerator, а за тем послать его одним Http запросом?(а не делать всё по отдельности)

private HttpResponse submitRestCall(String relativeUrl, String method, Object data){
Http h = new Http();
HttpRequest queryReq = new HttpRequest();
queryReq.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + TOOLING_API_URI + relativeUrl);
queryReq.setHeader('Authorization', 'OAuth ' + this.sessionId);
queryReq.setHeader('Content-Type', 'application/json');
queryReq.setMethod(method);
if(data!=null)
{
// Custom serializer?
if(data instanceof ISerialize)
{
ISerialize dataToserialize = (ISerialize) data;
JSONGenerator jsonGen = JSON.createGenerator(false);
jsonGen.writeStartObject();
dataToserialize.serialize(jsonGen);
jsonGen.writeEndObject();
queryReq.setBody(jsonGen.getAsString());
}
else
{
// Standard JSON serializer emits null values,
// which are generally not tolerated by Tooling API
queryReq.setBody(JSON.serialize(data));
}
}

HttpResponse queryRes = null;
try
{
queryRes = h.send(queryReq);
}

catch (System.CalloutException ce)
{
if (ce.getMessage().containsIgnoreCase('unauthorized endpoint'))
{
throw new ToolingAPIAuthorizationException(ce);
}
else
{
throw ce;
}
}

Integer successCode = 200;
if(method.equals('POST'))
successCode = 201;
else if(method.equals('DELETE'))
successCode = 204;
if(queryRes.getStatusCode() != successCode)
if(queryRes.getBody().length()>0)
throw new ToolingAPIException((List<ErrorResponse>) JSON.deserialize(queryRes.getBody(), List<ErrorResponse>.class));
else
throw new ToolingAPIException('Unexpected HTTP Status ' + queryRes.getStatusCode());
return queryRes;
}

[quote="Dmitry Shnyrev"][quote="Konstruktor"]Или есть возможность это "красиво" обойти?[/quote]
Делать тулу на на Apex, а на нормальном языке без лимитов.[/quote]

Ну, а если всё-таки на Apex? :)  Можно ли как-то сериализовать по очереди все объекты в один JSONGenerator, а за тем послать его одним Http запросом?(а не делать всё по отдельности) 

[code]private HttpResponse submitRestCall(String relativeUrl, String method, Object data){
        Http h = new Http();
        HttpRequest queryReq = new HttpRequest();
        queryReq.setEndpoint(URL.getSalesforceBaseUrl().toExternalForm() + TOOLING_API_URI + relativeUrl);
        queryReq.setHeader('Authorization', 'OAuth ' + this.sessionId);
        queryReq.setHeader('Content-Type', 'application/json');
        queryReq.setMethod(method);
        if(data!=null)
        {
            // Custom serializer?
            [b]if(data instanceof ISerialize)
            {
                ISerialize dataToserialize = (ISerialize) data;
                JSONGenerator jsonGen = JSON.createGenerator(false);
                jsonGen.writeStartObject();
                dataToserialize.serialize(jsonGen);
                jsonGen.writeEndObject();
                queryReq.setBody(jsonGen.getAsString());
            }
            else
            {
                // Standard JSON serializer emits null values, 
                //    which are generally not tolerated by Tooling API
                queryReq.setBody(JSON.serialize(data));
            }
        }

        HttpResponse queryRes = null;
        try
        {
            queryRes = h.send(queryReq);
        }[/b]
        catch (System.CalloutException ce)
        {
            if (ce.getMessage().containsIgnoreCase('unauthorized endpoint'))
            {
                throw new ToolingAPIAuthorizationException(ce);
            }
            else
            {
                throw ce;
            }
        }

        Integer successCode = 200;
        if(method.equals('POST'))
            successCode = 201;
        else if(method.equals('DELETE'))
            successCode = 204;
        if(queryRes.getStatusCode() != successCode)
            if(queryRes.getBody().length()>0)
                throw new ToolingAPIException((List<ErrorResponse>) JSON.deserialize(queryRes.getBody(), List<ErrorResponse>.class));
            else
                throw new ToolingAPIException('Unexpected HTTP Status ' + queryRes.getStatusCode());
        return queryRes;
    }[/code]

Вообщем, вроде получилось. Лимит по callout обошёл через AJAX Затем наткнулся на лимит по heap size, но он превышал только синхронный лимит(6 MB) и был меньше асинхронного(12 MB). Таким образом, проблема решилась через Queueable Apex. Пока всё, большое спасибо всем, кто отвечал, особенно wilder

Вообщем, вроде получилось. Лимит по callout обошёл через [url=http://sforcetips.blogspot.com.by/2013/06/saleforce-http-callouts-limit-workaround.html]AJAX[/url] Затем наткнулся на [url=https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_apexgov.htm]лимит по heap size[/url], но он превышал только синхронный лимит(6 MB) и был меньше асинхронного(12 MB). Таким образом, проблема решилась через [url=https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_queueing_jobs.htm]Queueable Apex[/url]. Пока всё, большое спасибо всем, кто отвечал, особенно wilder :)