5

I'm quering Apex classes using Tooling API

QueryResult queryResult = toolingConnection.query("select Id, ApiVersion, Name, NamespacePrefix, SymbolTable, Body from ApexClass where NamespacePrefix = null");

and I'm getting property SymbolTable as null. All the other fields I receive as it queried.

I have two developer edition accounts and with the second one it works just fine. And with the first account it WORKED fine about a week ago. I made some changes in code after that, but that was changes in other parts of code. And even if I changed something in code that was tightly coupled I don't have any idea what could be the reason for such behavior.

When I'm trying to receive it using MetadataContainer it doesn't work also.

What could be the reasons for that?

7

As per the ApexClass documentation.

If there is not a cached version of SymbolTable, it will be compiled in the background and the query might take longer than expected. The SymbolTable returned from ApexClass does not contain references; to retrieve a SymbolTable with references, use ApexClassMember.

So you need to use ApexClassMember to get the SymbolTable. If it is null, you need to use a MetadataContainer with an ApexClassMember and then a ContainerAysnRequest to compile it and populate the SymbolTable.

Rough steps to populate the ApexClassMember SymbolTable:

  1. Create a MetadataContainer via the API can get the Id.
  2. Create an ApexClassMember with the ContentEntityId set to the Apex Class Id and the Body as the existing body. Set the MetadataContainerId with the value from step 1.
  3. Create a ContainerAsyncRequest with the MetadataContainerId from step 1. Is IsCheckOnly to true (I believe this will be sufficient to populate the SymbolTable. Set it to false if you have issues.)
  4. Poll the ContainerAsyncRequest until the State changes from "queued".
  5. Retrieve the ApexClassMember again with the SymbolTable populated.

There is an example in Using Tooling SOAP API that goes through these steps more or less.

  • 1
    I've tried this also. I wrote When I'm trying to receive it using MetadataContainer it doesn't work also . Maybe it was not clear that I did all this actions that you listed :) But I did and it still doesn't work. And as it is said in that piece of documentation The SymbolTable returned from ApexClass does not contain references and I'm not talking about references. I'm talking about the whole SymbolTable. It should work without using ApexClassMember – Liudmila Likhovid Nov 27 '14 at 21:37
  • @LiudmilaLikhovid So the results after the ContainerAsyncRequest indicate that the compilation was successful? (ErrorMsg and DeployDetails). Is the ApexClass in question part of a managed package by chance? – Daniel Ballinger Nov 27 '14 at 21:55
  • @LiudmilaLikhovid I your SOQL query includes NamespacePrefix = null so it won't be a managed package issue. I suspect the classes aren't being successfully compiled. You could also check the ApexClass.IsValid column. – Daniel Ballinger Nov 27 '14 at 23:02
  • I've just found out that after doing all that steps to populate the ApexClassMember SymbolTable valid classes have SymbolTable. Thank you so much! I just didn't suppose that any of my classes are not valid. By the way could you please explain me what does that "isValid" mean? It seemed to me that SF doesn't allow to save classes that are not valid (that aren't successfully compiled). I thought that all classes that stored on server are valid – Liudmila Likhovid Nov 27 '14 at 23:54
  • 1
    One way ApexClasses before invalid is due to changes in other Apex Classes. Deployments via the Tooling API usually pickup the compile errors with dependant classes. However, this isn't always caught. So you can end up with Apex Classes in Salesforce that can't compile. – Daniel Ballinger Nov 28 '14 at 0:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.