1

I am trying to retrieve SymbolTable from Tooling API, but it takes too long to retrieve that. Also like when I try to access the SObject from the ToolingAPI package, I am not getting any option like this : sObject.getField("Name");. This option is only available when done through partner API, but the disadvantage in partner api is that it does not retrieve Symbol Table.

My question is will firing toolingConnection.retrieve on each loop slow my org performance or is it just the external application which is firing slows down? Also is there any other way to retrieve the Symbol table in batches?

My code to retrieve Symbol table is like this :

    // Get SymbolTable
    String apexClassBodytooling = "SELECT Id, Name, SymbolTable FROM APEXCLASS";
    List<String> idList = new ArrayList<>();

    List<com.sforce.soap.partner.sobject.SObject> sObjectList = queryRecords(apexClassBody, partnerConnection, toolingConnection, true);
    List<SObject> sObjectListTooling = queryRecords(apexClassBodytooling, partnerConnection, toolingConnection, false);

    for (SObject sObject : sObjectListTooling) {
        String[] stringArray = new String[1];
        stringArray[0] = sObject.getId();
        SObject[] apexClasses = toolingConnection.retrieve("SymbolTable, Id, Name", "ApexClass", stringArray);
        for (SObject sObjects : apexClasses) {
            ApexClass apexClass = (ApexClass) sObjects;
            SymbolTable symbolTable = apexClass.getSymbolTable();
            if (symbolTable == null) { // No symbol table, then class likely is invalid
                continue;
            }
            setValues(stringArray[0], apexClass, stringSymbolTableMap, symbolTable);
        }
    }


    private static void setValues(String id, ApexClass apexClass, Map<String, SymbolTable> stringSymbolTableMap, SymbolTable symbolTable) {
    if (id.equals(apexClass.getId())) {
        stringSymbolTableMap.put(apexClass.getName(), symbolTable);
    }
    }


    public static <T> List<T> queryRecords(String query, PartnerConnection partnerConnection, ToolingConnection toolingConnection, boolean usePartner)
        throws com.sforce.ws.ConnectionException {
    if (usePartner) {
        List<T> sObjectList = new ArrayList<>();
        QueryResult qResult;
        qResult = partnerConnection.query(query);
        boolean done = false;
        if (qResult.getSize() > 0) {
            System.out.println("Logged-in user can see a total of "
                    + qResult.getSize() + " contact records.");
            while (!done) {
                com.sforce.soap.partner.sobject.SObject[] records = qResult.getRecords();
                for (com.sforce.soap.partner.sobject.SObject record : records) {
                    sObjectList.add((T) record);
                }

                if (qResult.isDone()) {
                    done = true;
                } else {
                    qResult = partnerConnection.queryMore(qResult.getQueryLocator());
                }
            }
        } else {
            System.out.println("No records found.");
        }
        System.out.println("Query successfully executed.");

        return sObjectList;
    } else {
        List<T> sObjectList = new ArrayList<>();
        com.sforce.soap.tooling.QueryResult qResult = toolingConnection.query(query);
        boolean done = false;
        if (qResult.getSize() > 0) {
            System.out.println("Logged-in user can see a total of "
                    + qResult.getSize() + " contact records.");
            while (!done) {
                SObject[] records = qResult.getRecords();
                for (SObject record : records) {
                    sObjectList.add((T) record);
                }
                if (qResult.isDone()) {
                    done = true;
                } else {
                    qResult = toolingConnection.queryMore(qResult.getQueryLocator());
                }
            }
        } else {
            System.out.println("No records found.");
        }
        System.out.println("Query successfully executed.");

        return sObjectList;

    }
}

I even tried placing the ids in an array and passing it at once, but as the ids are more than 4000, it throws exception.

    String apexClassBodytooling = "SELECT Id, Name, SymbolTable FROM APEXCLASS";
    List<String> idList = new ArrayList<>();

    List<SObject> sObjectListTooling = queryRecords(apexClassBodytooling, partnerConnection, toolingConnection, false);


    for (com.sforce.soap.partner.sobject.SObject sObject : sObjectList) {
        String Id = (String) sObject.getField("Id");
        idList.add(Id);
    }



    String[] classArray = new String[idList.size()];
    classArray = idList.toArray(classArray);

    SObject[] apexClasses = toolingConnection.retrieve("SymbolTable, Id, Name", "ApexClass", classArray);
  • You're querying the SymbolTable and then querying it again? – sfdcfox Mar 18 '18 at 17:07
  • The SymbolTable which we get from the first query cannot be retrieved as sObject from tooling API does not have any method as Partner API has like : sObject.getField("Name"); – Nagendra K S Mar 19 '18 at 0:53
0

Casted the retrieved query result to ApexClass from Tooling API as I was returning a generic result.

Now I can access the symbol table. @sfdcfox thanks for pointing the double query.

    List<ApexClass> sObjectListTooling = queryRecords(apexClassBodytooling, partnerConnection, toolingConnection, false);

    for (ApexClass apexClasses : sObjectListTooling) {
        SymbolTable symbolTable = apexClasses.getSymbolTable();
        String name = apexClasses.getName();
        setValues(name, stringSymbolTableMap, symbolTable);
    }

private static void setValues(String name, Map<String, SymbolTable> stringSymbolTableMap, SymbolTable symbolTable) {
    stringSymbolTableMap.put(name, symbolTable);

    }

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.