18

Question about how static member/method inheritance works in apex:

For reference, this question is related, but doesn't address my question or take into account my findings: reference question

I have a factory base class, with only static members and methods that are not allowed to be declared virtual:

public virtual class Fact_BaseFactory 
{
    /******** MEMBERS REGION ********/

    private static Map<String, Schema.DisplayType> fieldNameToTypeMap = new Map<String, Schema.DisplayType>();

    private static Map<String, ID> recordTypes = new Map<String, ID>();

    /******** PRIVATE HELPER REGION ********/

    //attaches newly inserted, factory-produced lookup record
    private static void populateFieldNameToTypeMap(String objectName)
    {
         List<String> objNames = new List<String>();
         objNames.add(objectName);
         Schema.DescribeSobjectResult objDescribe = Schema.describeSObjects(objNames)[0];
         for (Schema.SObjectField objectFields : objDescribe.fields.getMap().values())
         {
             Schema.DescribeFieldResult fieldDescribe = objectFields.getDescribe();
             fieldNameToTypeMap.put(fieldDescribe.getName(), fieldDescribe.getType());
         }
     }
}

Which I use to extend an SObject factory from:

global class Fact_Account extends Fact_BaseFactory
{
    public class AccountFactoryException extends Exception { }

    //define default constants
    public static final String DEFAULT_NAME = 'FactoryAccount';
    public static final String DEFAULT_ENTITY_Id = 'Foo_North_America';


    /******** STATIC INITIALIZATION REGION ********/

    static 
    {
        //base class method
        super.populateFieldNameToTypeMap('Account');        

        //base class member
        recordTypes = UtilityMethods_Data.mapOfAccountRecordTypes();
    }

    //rest of class
}

My question is about the SUPER keyword seen here in the static initialization block of the subclass. The code as shown compiles correctly, but if I remove the super keyword, I get a 'Variable does not exist: recordTypes' error because the static members/methods are not inherited from the base class.

However, because I use the super keyword to reference a method from the base-class, somehow this allows me to directly reference all of the static members/methods of the base class in the subclass (without super keyword), as long as I use the super keyword to call a base-class method (HAS to be method) before the super-less base-class reference (member OR method).

Without the super keyword, the compiler seems to search for base-class members first to error on, and if there are no base-class members it errors on base-class method references. I think that's due to compilation-step order and not because of different treatment of static member vs static method on the base class.

  1. Is this a known/acceptable use of SUPER to enable inheritance from one wholly static class to another wholly static class?
  2. Is this a poor design because it's not readable/maintainable anyway, with two options I can see to replace:

a) Change Fact_BaseFactory into a utility class (Fact_FactoryHelper) with all static methods, and move static members from base into ex-subclasses (violates DRY).

b) Composition instead of inheritance.

Thanks!

  • I'm guessing it's a bug along the lines of compiling public class MyClass<T> { }, but then not allowing you to re-compile the code. – sfdcfox Dec 20 '14 at 0:52
  • TIL Salesforce Apex supports instance and static initializers. Did not know! – bigassforce Dec 20 '14 at 1:21
2

First of all your code doesn't compile now. That explains a lot.

Secondly, in my opinion messing with polymorphism in static classes (wholly static as you said) is not a good design at all. I don't see any good reason (although there might be some) driven by design needs to do try to access static method with super. But question is still interesting, so let's move on.

Third thing is, you use super keyword to reference private member. It shouldn't be possible at all. Private is private. If it compiled somehow, that was certainly a bug.

Answering to point 1: As I said, I can't see any reason to inherit from static class. Actually It's not even an inheritance, you can access public members of any other static class anyway like listed below. Moreover, it's not permitted now - when I tried to compile your code (and many of it's variations :) I get the Variable does not exist: this error from line -1 (valuable clue!). Not surprisingly, the code like this works fine, and it doesn't grant any access to other private members:

public virtual class Fact_BaseFactory 
{
    public static void populateFieldNameToTypeMap(String objectName) { ... }
}



public class Fact_Account extends Fact_BaseFactory
{
    static 
    {
        Fact_BaseFactory.populateFieldNameToTypeMap('Account');
    }
}

According to second question:

A) This idea seems to be the way to go, I would just create some public method In the helper class and reuse the code within your factories. Not sure what you mean with violating DRY here.

B) Composition instead of inheritance is good design in general based on my experience and it's also recommended by Head First "Design Patterns" book. I would stick to the A anyway, but it's a good question to ask on codereview.stackexchange.com

| improve this answer | |
  • 1
    Hi Bart, thanks for the detailed analysis. Really appreciate your input. SfdcFox turned me on to the false-positive compilations that can happen, especially with the Tooling API, and I was able to determine that my code was never truly compiling anyway. I ended up adopting composition to solve this problem. You've added some great detail to my understanding of how to architect in the future. Thanks. I open-sourced the code, so you can see the implementation here: github.com/DavidWaughSFDC/SFDC-Flexible-Factory-Methods/blob/… – DavidWaugh Mar 5 '15 at 19: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.