+ Start a Discussion
vijaynvijayn 

Apex Language Bug or is the protected keyword working as per design?

I see what looks like a language bug in Apex (either that, or 'protected' has a surprising meaning in Apex).

 

According to the language reference: protected is defined as:

"This means that the method or variable is visible to any subclasses in the defining Apex class". Note that it says any *subclasses* *in* the defining apex class.

 

Here's what I see:

 

 

public class TestClass { public abstract class Base { protected abstract String protected_method(); public void protected_method_caller() { System.debug('Returning ' + protected_method()); } protected void is_this_really_protected() { System.assert(true, 'Not true'); System.debug('this is a test'); } } public class Derived extends Base { protected override String protected_method() { System.debug('Calling protected method'); System.assert(true, 'Not True'); return 'Test'; } } public class UnRelated { public void unrelated_method() { Derived d = new Derived(); d.is_this_really_protected();// THIS LINE SHOULD FAIL AS UNRELATED IS NOT A SUBCLASS

} } public testmethod static void test_protected_method() { Derived d = new Derived(); d.protected_method_caller(); } public testmethod static void test_unrelated_method() { UnRelated u = new UnRelated(); u.unrelated_method(); } }

 

In the above test case,  an unrelated inner class is able to call a protected method(as long as it is defined in the same outer class). (Ie. It is *in* the same defining class but not a *subclass*)

 

Now consider this:

 

// In base.cls public abstract class Base { protected abstract String protected_method(); public void protected_method_caller() { System.debug('Returning ' + protected_method()); // QUITE LEGITIMATE. SHOULD WORK! } } // In derived.cls public class Derived extends Base { protected override String protected_method() { System.debug('Calling protected method'); System.assert(true, 'Not True'); return 'Test'; } public static testmethod void testderived() { Derived d = new Derived(); d.protected_method_caller(); } }

 

What, to me, seems a fairly normal use of protected. Running this test fails with:

System.TypeException: Method is not visible: [Derived].protected_method()  

 

In this case, Base cannot see the overriden Derived protected_method(). NOTE: If I change the modifier in Derived to public override protected_method() {...}, it works. (Ie. it is a *subclass* but not *in* the same defining class.

 

Is this how it's supposed to behave? Or is this a bug?

 

thanks,

Vijay

 

Keith654Keith654

I just ran in to this too a long time after you. You might think if it was "by design" that the problem would be reported at compile time rather than at runtime. Either way its unfortunate behavior that is both inconsistent with the common understanding of what "protected" means and undermines using design patterns like template method. Yuk.

haridsvharidsv

I think it is per design, considering how protected works in Java, which is to give access to derived classes as well as package members. If you think of TestClass as equivalent to a package in Java, then it would be appropriate to have the visibility for all inner classes of TestClass as they all belong to "same package". In fact, you don't even need to go as far as correlating TestClass with a package, but you can see that an equivalent Java code will work just fine. I could get the below Java code to compile (which by itself is proof enough) and run:

 

public class TestClass {

    public static abstract class Base {
        protected abstract String protected_method();
        public void protected_method_caller() {
            System.out.println("Returning " + protected_method());
        }

        protected void is_this_really_protected() {
            System.out.println("this is a test");
        }
    }

    public static class Derived extends Base {
        protected String protected_method() {
            System.out.println("Calling protected method");
            return "Test";
        }
    }

    public static class UnRelated {
        public void unrelated_method() {
            Derived d = new Derived();
            d.is_this_really_protected(); // THIS SHOULD COMPILE AND WORK JUST FINE
        }
    }

    public static void test_protected_method() {
        Derived d = new Derived();
        d.protected_method_caller();
    }

    public static void test_unrelated_method() {
        UnRelated u = new UnRelated();
        u.unrelated_method();
    }

    public static void main(String[] args) {
        TestClass.test_protected_method();
        TestClass.test_unrelated_method();
    }
}

The reason this works in Java is that inner classes of a class are by definition part of the same package as the outer class, so any protected methods defined by one of the inner classes has to be accessible to any other inner class or the outer class.

 

See the answer to this question for understanding visibility in Java: http://stackoverflow.com/questions/215497/in-java-whats-the-difference-between-public-default-protected-and-private