0

I am not able to find regular expression for getting only the methods from a class body which is in String format.

 Apexclass sampleApexClass = [SELECT body from ApexClass Where name = <SomeClass>];
 Pattern regPattern = Pattern.compile('(Public Static)\\s*(\\w+)\\s*(\\w+)\\(.*?\\)\\s*(\\{(?:\\{(?:\\{[^\\{\\}]*\\}|.)*?[^\\{\\}]*\\}|.)*?\\})');
 Matcher regMatcher = regPattern.matcher(sampleApexClass.body);

Getting Error Like : "No Match Found"

I am guessing that this is happening because of "?" character in the regular expression. Can some one help me to find correct regular expression to find the method bodies from a class body in string format.

2 Answers 2

2

On top of what David has mentioned, the simplest way for you to retrieve the method names (and other details) from an apex class will be to use Tooling API.

You can retrieve the SymbolTable for the class and then fetch all the method details from the class declaration.

This link has an example on how to do so. Something that I have done in the past (in Java) for a similar scenario was as below:

QueryResult apexClasses = stub.query("select Id, Name, SymbolTable from ApexClass where Name =<my apex class>)";
ApexClass cls = (ApexClass) apexClasses.getRecords(0);
SymbolTable symTable = cls.getSymbolTable();

if(symTable != null) {
    Method [] methods =  symTable.getMethods(); // this gives you all the methods declared in your class 
    for(Method m : methods) {
        ...do your stuff...
    }
}  

The Method class will provide you with the following details (to name a few), which you can utilize per your requirements.

  • Name
  • Modifiers
  • Return Type
  • Visibility
  • Parameters

With this approach, you rely on the platform provided API here without the need of parsing your class and matching the pattern, which could be error prone, as David has pointed.

1

Let's try to break this down to highlight a few problems. Apex syntax not being especially amenable to regex parsing, I'm very skeptical this approach will ever work effectively and with full generality. I would rather call out to the Tooling API and work with the symbol table access provided there, if that's enough to achieve whatever your actual end goal is. (See Andrew Fawcett's old blog post on finding dead code in Apex for an example of that approach).

The Java Pattern documentation is a critical reference here.

Basically, it kind of works if you provide the correct flags. You need the (?si) flag element, asking for case-insensitive matching and dotall mode, where . will match a newline. Here's an example of this working correctly:

String q;

q = 'class Test {\n' +
    '    public static void test(Integer i) { \n'+
    '       if (true) { \n' +
    '           test2(1); \n' +
    '       }\n'+
    '}\n';

Pattern regPattern = Pattern.compile('(?si)(Public Static)\\s*(\\w+)\\s*(\\w+)\\(.*?\\)\\s*(\\{(?:\\{(?:\\{[^\\{\\}]*\\}|.)*?[^\\{\\}]*\\}|.)*?\\})');
Matcher regMatcher = regPattern.matcher(q);

while (regMatcher.find()) {
    System.debug('group:' + regMatcher.group());

This does in fact log the right value - the text of the method test(). The problem is that it's really easy to break: just add a second method.

q = 'class Test {\n' +
    '    public static void test(Integer i) { \n'+
    '       if (true) { \n' +
    '           test2(1); \n' +
    '       }\n'+
    '    public static void test2(Integer i) \n' +
    '        {' +
    '    test(2);' +
    '    }\n' +
    '}\n';

This gets you back only a single group, containing the text of both methods. (I don't immediately have a recommendation for how to fix this).

There's lots of other ways to break this, a couple of which I'll note below.

(Public Static)\s*

If we're only matching public static methods, okay. What if the method's declared static public? This won't match, and that's perfectly legal Apex. Additionally, regexes are case sensitive unless specified otherwise, so this won't actually match unless your methods are declared with Uppercase Modifiers or you specify (?i) as above.

(\w+)\s*

This looks like it's supposed to match the type name of the return type. But the \w character class includes alphanumerics and underscores only, and Apex type names also include <>. So any method that returns a parameterized type will fail to match.

Inner classes may pose other issues - I didn't even try testing with an inner class present.

In general, it's not a good idea to "send a regex to do a parser's job". Far more stable an approach is to trust the actual Apex compiler by talking to the Tooling API or doing your work on the tooling/development side rather than in Apex itself.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .