0

I am trying to save an batch apex class dynamically via the tooling api.

//I want the batch class to be of the sObject type that user wants.
//Regex replaces %s with className provided by the user.
//Then I post the class via Tooling API.
public class TestBatchExecute {
    public String batchClass='public class TestBatch implements Database.Batchable<%s>{\npublic System.Iterable<%s> start(Database.BatchableContext bc){\nreturn Database.getQueryLocator(\'select id,name from \'+ %s);\n}\npublic void execute(Database.BatchableContext bc,List<%s> scope){for(%s obj:scope){\nsystem.debug(obj);\n}\n}public void finish(Database.BatchableContext bc){system.debug(\'done job\');}}';
    public TestBatchExecute(String className){
        if(Schema.getGlobalDescribe().containsKey(className)){
            try{
                batchClass = batchClass.replaceAll('%s',className);
                System.debug(batchClass);
               
                if(NetworkUtils.generatePostResponse('ApexClass/',JSON.serialize(new PostObject('TestBatch',batchClass)))){
                    system.debug('goodmate');
                }
            }catch(StringException se){
                system.debug(se);
            }
        }
    }
}

Then in the anonymous window : -

new TestBatchExecute('Account');

I get the following error : -

{"message":"Variable does not exist: Account","errorCode":"INVALID_FIELD_FOR_INSERT_UPDATE","fields":[]}```

4
  • Any work around for my requirement ? Commented Jul 14, 2021 at 16:14
  • Please edit your post and describe your higher-level goals.
    – identigral
    Commented Jul 14, 2021 at 16:22
  • I have edited the post. Commented Jul 14, 2021 at 16:31
  • As a side note, have you seen this answer? I wrote it a while ago, it may serve your purpose as well.
    – sfdcfox
    Commented Jul 14, 2021 at 20:13

1 Answer 1

1

The error happened because your code compiled to:

'select id,name from '+ Account

Which is invalid.

This code:

\'select id,name from \'+ %s

Should be:

[select name from %s]

Note that I recommended you change to an inline query. This will help prevent code that compiles but doesn't run.


As a side note, it's rarely necessary to do this; if you use sObject, it can handle any type of object.

public class BatchableWhatever implements Database.Batchable<sObject> {
  string objectToQuery;
  public BatchableWhatever(sObjectType objectType) {
    objectToQuery = objectType.getDescribe().getName();
  }
  public Database.QueryLocator start(Database.batchableContext context) {
    return Database.getQueryLocator('select name from '+objectToQuery);
  }
  public void execute(Database.batchableContext context, sObject[] scope) {
    for(sObject record: scope) {
      System.debug(record.get('Name'));
    }
  }
  public void finish(Database.BatchableContext context) {
    System.debug('Done!');
  }
}

Also the note of a sObjectType token. This saves you a global describe, because the code can't have typos.

You must log in to answer this question.

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