Namespace shadowing and namespace prepending in Salesforce

First of all, this post is about managed package development.

When developing managed package, usually development takes place in unnamespaced scratch org or sandbox in personal scratch org or personal sandbox per each developer and then the code is merged together inside a developer branch in version control system like Git on git repository system like Github or Gitlab and then the code from developer branch is build into 2GMP version by SFDX or deployed into packaging org for 1GMP and a package version is built there.

There are some peculiarities and differences between having packaged namespaced code and unpackaged code without namespace. Also, sandboxes cannot have namespace. Still, scratch org support namespace. So one of the possible way of development might be working with namespaced scratch orgs and hard-coding namespaces there. On my recent project I couldn’t go with that route since when we started project development we didn’t have access to the client namespace so we couldn’t hardcode it. For POC and MVP we were building the package with my personal namespace and then we rebuilt it with client namespace one they have setup it on devhub but before that time we were expected to deliver some results and show how managed packages work.

So even if we used namespaced scratch org and started hardcoding namespaces there, it wouldn’t work for us since when we got access to devhub with presetup client namespace we would have then to change every hardcoded namespace into another one. So we ended up using dynamic namespace prepending. But before we deep dive into that let’s discover what is namespace shadowing and what are the other options.

Namespace shadowing is a term which describes how Apex code works with custom objects and fields inside a managed package. Let’s assume we have a custom object CustomObject__c with a custom field CustomField__c. When we want to query this record, we write as follows:

CustomObject__c record = [SELECT CustomField__c FROM CustomObject__c LIMIT 1];

Let’s assume now we build a package with namespace ns and try to run the same code in the same class, it would work without any issue inside packaged class. If we want to access this object by unmanaged code on the org where the package is installed, we would have to prepend a namespace like follows:

ns__CustomObject__c record = [SELECT ns__CustomField__c FROM ns__CustomObject__c LIMIT 1];

We could also use the same query inside a package assuming we are deploying that code into a packaging org for 1GMP or to namespaced scratch org. However, we wouldn’t be able to deploy that code into unnamespaced scratch org or a sandbox.

Assume that a customer created a custom field with coincides with the name of our packaged field, and now on custom object ns__CustomObject__c there are two fields: ns__CustomField__c and CustomField__c. Now field CustomField__c is not available to our package, since anytime if we try to refer it in a static SOQL or dynamic SOQL, a namespace prefix will be automatically prepended and internally CustomField__c will be changed into ns__CustomField__c and packaged code will not be able to access it. If, however, a field will be created with a different name like CustomField1__c and there are no such field with such name inside a package, this field will be available to access, since when apex tries to access such field, and it doesn’t find it in a package, it accesses it without namespace. This is how namespace shadowing works.

Now let’s go further. If we try to refer an object or a field inside a FrontEnd like Visualforce Javascript, LWC or retired Aura. then there will be no namespace shadowing. That means we would have to prepend prefix ourselves or decide another options. Which options do we have?

Option 1. Create DTO model class and refer in LWC or Visualforce that class instance and properties instead of object or fields.

public inherited sharing class CustomObjectDTOModel {

@AuraEnabled public String customField {get; set;}

public CustomObjectDTOModel(CustomObject record) {

customField = record.CustomField__c;

}

}

Now instead of passing directly an Object like follows:

public inherited sharing class Controller{

@AuraEnabled @RemoteAction

public static CustomObject__c getRecord() {

return [SELECT CustomField__c FROM CustomObject__c LIMIT 1];

}

}

we change this into

public inherited sharing class Controller{

@AuraEnabled @RemoteAction

public static CustomObjectDTOModel getRecord() {

return new CustomObjectDTOModel([SELECT CustomField__c FROM CustomObject__c LIMIT 1]);

}

}

and we refer not to CustomField__c field but to DTO Model property customField which is namespace agnostic.

Option 2. Automatically prepend namespace before building a package version.

For example, we still need to prepend namespace in some other places. When one LWC parent refers another LWC child, inside a unnamespaced org, it should look <c:child> but when it is inside a packaged code, it should looke like <ns:child>

We can use some script like follows

rm -r force-app

cp -r ../unpackaged/force-app .

namespace=$(cat sfdx-project.json | jq ‘.namespace’ -r)

find force-app -type f \( -name “*.app” -o -name “*.component” -o -name “*.page” \) -exec sed -i ” “s/c:/$namespace:/g” {} \;

to replace every <c:child> with <ns:child> in every LWC, VisualforcePage or Lightning App. We could implement a similar script for namespacing fields, but in this case it is hard to determine a generic replace rule unless we follow some convention. For example, if we agree to have every field started with F_ we then could potentially have script like

find force-app -type f \( -name “*.app” -o -name “*.component” -o -name “*.page” \) -exec sed -i ” “s/ F_/ ${namespace}F_:/g” {} \;

Option 3. Instead of hardcoding or mingling with namespaces manually or by CI/CD script, we could use dynamic namespace prepending. This approach works in the following way.

First of all, we need to determine if we are inside a managed package or unpackaged code.

If we know that we have a CustomObject__c with a CustomField__c inside our package, we can refer to Namespace Shadowing to determine that. if namespace shadowing occurs, we are inside a managedd package and if it doesn’t occur, we are inside an unmanaged unpackaged code.

public static String getNamespace() {

Schema.DescribeFieldResult dfr = CustomObject__c.CustomField__c.getDescribe();

return dfr.getName().remove(dfr.getLocalName());

}

public static String getBareNamespace() {

String prefix = getNamespace();

return prefix.left(prefix.length() – 2);

}

This is not the only option but just one of the many options available to determine namespace.

Now whenever we want to know namespace, we can call getNamespace method to get it. We may cache it not to call it many times during a single transaction but for the sake of simplicity I don’t show caching code here.

Inside our example, getNamespace() method will returnthe whole prefix ns__, the namespace and double underscore for the packaged code and empty string for unpackaged code. If we need just the bare namepsace without double underscore insertion, we might use getBareNamespace() method.

We may use getBareNamespace() method if we for example, have both namespaced and unnamespaced permission set with the same name and we want to distinguish them.

For example, if we want to query all users who are assigned packaged permission set.

[

SELECT Email, FirstName, LastName, UserName

FROM User WHERE Id IN (

SELECT AssigneeId FROM PermissionSetAssignment

WHERE PermissionSet.Name = ‘PermissionSet’ AND PermissionSet.NamespacePrefix =: getBareNamespace()

)

];

I hope this is helpful for you.

This entry was posted in apex, namespace, package and tagged , , , , , . Bookmark the permalink.

Leave a comment