[SalesForce] Can create an Instance of Abstract Class, Salesforce Bug

I was playing with Apex and stumbled upon this.

Created an Abstract Class and made the constructor as private, so that noone can create an instance of it. This works just fine during compilation. it stops me from using new AbstractClass(). Which is awesome.

Then I thought can I use JSON Deserialize to create an instance of the abstract class with private constructor, and I was able to.

public  Abstract class  MyAccountWrapper {

    public  String abc;

    private  MyAccountWrapper(){
        System.debug(abc);
        System.debug('Constructor called');
    }



}

Test:

MyAccountWrapper myc = (MyAccountWrapper)JSON.deserialize('{"abc":"JAR"}',MyAccountWrapper.class);

System.debug(myc.abc); // Prints "JAR"

I also noted that Constructor was not called, thus the private bit of constructor didn't came into the picture during deserialization.

Is it SF bug or working as designed?

Also, When I try that as Interface instead of Abstract class, I get an exception.

Error on line 15, column 1: System.TypeException: Cannot deserialize JSON as abstract type: MyAccountWrapper
Class.System.JSON.deserialize: line 15, column 1

My understanding is Abstract class and Interfaces can't be instantiated. Which does not hold true for Abstract class.

Can someone shed some light?

Best Answer

Edit: This is now explicitly blocked in a critical update that prevents one from deserializing a JSON object into an abstract class. See also @ca_peterson's answer, Tweet, and GitHub comment, and the Release Notes/Critical Update.

Future Readers: If there is not a link to the Critical Update/Release Notes announcing this feature, please feel free to comment or edit a link in to this answer (see [4]: at the bottom of this post in edit mode).


Original Answer

abstract is a compiler-enforced limitation. The runtime does not explicitly check for abstract or read-only properties for performance reasons. JSON.deserialize is a common trick we've used for ages to mock an sObject with read-only fields, etc. Just be aware that if you do use this trick, be very careful, as you'll run into exceptions if you try to call an abstract method. Interfaces can't be deserialized because they're not "real" classes in the same sense. Technically, this is "working as designed," but you should avoid abusing this feature any more than necessary.

Related Topic