0

I want to create a query which gets for me the apex classes that we can schedule. I already know know the query to get all the apex class classes, but i only want the classes that can be scheduled.

2 Answers 2

5

The closest you can get to this would be to use SOSL:

ApexClass[] schedulableClasses = (ApexClass[])
  [FIND "schedulable" IN ALL FIELDS RETURNING ApexClass(NamespacePrefix, Name)][0];

This is not foolproof, as it could return classes that merely have this in a comment or something, but you can then try to instantiate each one to see if it really implements the schedulable interface:

ApexClass[] realSchedulables = new ApexClass[0];
for(ApexClass klass: schedulableClasses) {
  try {
    Object t = Type.forName(klass.Name).newInstance();
    if(t instanceOf Schedulable) {
      realSchedulables.add(klass);
    }
  } catch(TypeException e) {
    // Ignore
  }
}

Note that this will won't work for classes that don't have a default constructor, and there's no way to figure this out short of parsing the class manually.


Edit: The following should work for all classes (thanks to @IllusiveBrian for the suggestion):

ApexClass[] realSchedulables = new ApexClass[0];
for(ApexClass klass: schedulableClasses) {
  try {
    Object t = JSON.deserialize('{}', 
      klass.NamespacePrefix == null? 
        Type.forName(klass.Name):
        Type.forName(klass.NamespacePrefix, klass.Name));
    if(t instanceOf Schedulable) {
      realSchedulables.add(klass);
    }
  } catch(TypeException e) {
    // Ignore
  }
}
5
  • JSON.deserialize('{}', Type.ForName(t)); should work regardless of whether the class has a default constructor. Wouldn't work for some standard objects, but I think anything from ApexClass should work. Commented Jul 1, 2019 at 14:01
  • I replaced "schedulable" with ' implements schedulable' in order to decrease the percentage error with other classes. Commented Jul 1, 2019 at 14:04
  • @IllusiveBrian That's a good point, actually. I keep forgetting how useful JSON.deserialize can be.
    – sfdcfox
    Commented Jul 1, 2019 at 14:07
  • In case if you have an abstract class which implements schedulable, and then dozens of ancestors which are not implementing "Schedulable", then ancestors are not returned. Those ancestors can be even a inner classes, which makes this original assignment a bit more complicated
    – kurunve
    Commented Jul 1, 2019 at 14:26
  • 1
    @kurunve Yes, there's no "perfect" method, but what we have is about the best we can do given the limitations of the language.
    – sfdcfox
    Commented Jul 1, 2019 at 15:29
0

Adding my 2 cents here.

From Winter 23, Salesforce has come up with ApexTypeImplementor object which can be used to get information on the Apex Classes which directly or indirectly implement an interface - https://developer.salesforce.com/docs/atlas.en-us.object_reference.meta/object_reference/sforce_api_objects_apextypeimplementor.htm

Since in your scenario, you want to get all the apex classes which can be scheduled (essentially classes with interface name - Scheduable), you can do a following SOQL

SELECT Id, ClassName, InterfaceNamespacePrefix from ApexTypeImplementor where InterfaceName = 'Schedulable'

Do note that this object is available in API version 54.0 and later.

You must log in to answer this question.

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