I may need to make many
@RestResource
Apex classes run eitherwith sharing
orwithout sharing
where that option is selected at runtime.But this approach (that I am using at present):
/** * Allow code to run "with sharing" or "without sharing" based on configuration. */ public inherited sharing class Sharing { public interface Executable { Object execute(Object[] args); } // With private with sharing class WithSharing { public Object execute(Executable executable, Object[] args) { return executable.execute(args); } } // Without private without sharing class WithoutSharing { public Object execute(Executable executable, Object[] args) { return executable.execute(args); } } // // Execute the code with or without sharing based on this documentation... // // Both inner classes and outer classes can be declared as with sharing. // The sharing setting applies to all code contained in the class, // including initialization code, constructors, and methods. // Inner classes do not inherit the sharing setting from their container class. // public static Object apply(Executable executable, Object[] args) { // TODO from config Boolean withSharing = false; if (withSharing) return new WithSharing().execute(executable, args); else return new WithoutSharing().execute(executable, args); } // No-args public static Object apply(Executable executable) { return apply(executable, new Object[] {}); } }
is quite ugly to add to the many classes (that have
static
entry points) e.g.:@RestResource(urlMapping='...') global inherited sharing class MyRest { @HttpPost global static Result post() { return (Result) Sharing.apply(new Executable()); } private inherited sharing class Executable implements Sharing.Executable { public Object execute() { return postWithSharingApplied(); } } // The content of the original post method private static Result postWithSharingApplied() { ... } ... }
Is there a cleaner way to do this?
PS
A follow-up question is Inherited sharing question in nested inner classes.
PPS
A key point is that the class containing the business logic
MyRest
above must not be declared aswith sharing
orwithout sharing
so is best declared asinherited sharing
. (I originally didn’t realize this.) This makes each business logic method also haveinherited sharing
.The key sentences from the documentation about this are:
The sharing setting of the class where the method is defined is
applied, not of the class where the method is calledand:
A class declared as inherited sharing runs as without sharing only
when explicitly called from an already established without sharing
context.
Answer
Your code is overly complicated because you presumed you needed an inner class in your RestResource class. You don’t.
The main problem is that you’ve reinvented the wheel with Sharing.Executable. There’s already an interface that does what you want: Callable.
First, let’s rewrite your Sharing class to use Callable:
public class Sharing {
public abstract class Base {
public Base() { /* default constructor */ }
public Object call(Callable source, String action, Map<String, Object> args) {
return source.call(action, args);
}
}
with sharing class withSharing extends Base { }
without sharing class withoutSharing extends Base { }
public static Object apply(Callable source, String action, Map<String, Object> args) {
// TO-DO From Config
//
Boolean withSharing = true;
return
(withSharing? (Base)new withSharing(): (Base)new withoutSharing())
.call(source, action, args);
}
}
Now, we can move the code to the top-level class:
@RestResource(urlMapping='...')
global class MyRest implements Callable {
public Object call(String action, Map<String, Object> args) {
switch on action {
when 'POST' { return postWithSharingApplied(); }
when else { reurn null; }
}
}
public static Result dispatch(String action) {
return (Result)Sharing.apply(new MyRest(), action, new Map<String, Object>());
}
@HttpPost
global static Result doPost() {
dispatch('POST');
}
// The content of the original post method
static Result postWithSharingApplied() {
...
}
...
}
The call
method adds a bit of overhead for a single method, but will save space with 2 or more methods used. Arguably, it also minimizes the amount of work you need to do once converted to the new format.
Notice, we don’t need inherited sharing
here at all. The sharing is enforced by the inner classes. You can choose to use the inherited sharing
keyword if you’d like, but it has no practical effect from what’s written here (although, if you need to pass an AppExchange Security Review, you’ll want to use it).
Attribution
Source : Link , Question Author : Keith C , Answer Author : sfdcfox