Clean way to vary sharing at runtime in Apex?

I may need to make many @RestResource Apex classes run either with sharing or without 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 as with sharing or without sharing so is best declared as inherited sharing. (I originally didn’t realize this.) This makes each business logic method also have inherited 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 called

and:

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

Leave a Comment