2

Let's say we have global ProductFactory class like this:

global class ProductFactory {

    global static ProductService getProductService() { 
        return new ProductServiceBasic();
    }

}

Also there is global ProductService interface (it's located inside ProductFactory class):

global interface ProductService {

    List<String> getAllProducts();

    List<String> getProductTypes();

}

And finally we have class-implementation of ProductService (as an inner class in in ProductFactory class as well), which is private for now with public methods coming from global interface:

private virtual class ProductServiceBasic implements ProductService {

    public List<String> getAllProducts() { ... }

    public List<String> getProductTypes() { ... }

}

Now we need to be able to use all of this outside of our package, like this:

    Boom.ProductFactory.ProductService service = Boom.ProductFactory.getProductService();

    List<String> productTypes = service.getProductTypes();

Question here is: do we need to make global ProductServiceBasic class? do we need to make all methods of this class global as well? It's not quite obvious, since ProductService and ProductFactory are referenced explicitly in this snippet above on subscriber org, but ProductServiceBasic is like an implicit asset which is accessed only via global ProductService interface. In other words, if we want to prevent subscriber from using ProductServiceBasic directly and force them to go only via global ProductService interface, can we keep ProductServiceBasic as private class with just public methods or would the above snippet throw an exception?

  • Have you tested it? This seems like something you should be able to figure out by performing some pretty simple tests. – gNerb Nov 20 '19 at 15:38
  • @gNerb Yes, I did. It seems to be working without global. But I don't see anything like that mentioned in official documentation. And there is a lot of quite contradictory info on the web. So not sure whether this is official well-established approach or just a bug which SF would fix in the future). – wesaw Nov 20 '19 at 15:45
2

I may be taking my experience for granted as I don't have any documentation to support my answer.

This seems like a pretty straightforward scoping question. I would expect what you have to always work:

Boom.ProductFactory.ProductService service = Boom.ProductFactory.getProductService();

List<String> productTypes = service.getProductTypes();

But I would expect this to always fail:

Boom.ProductFactory.ProductService service = new Boom.ProductFactory.ProductServiceBasic();

List<String> productTypes = service.getProductTypes();

The reason being in your first example you are never directly referencing the private class from outside of the global ProductFactory class. Instead you are referencing an instance of that class that was provided to you by the service. This is roughly the same reason we can have a private member with a public getter/setter. The getter/setter will touch the private member as it has the access to do so and if you attempt to access it directly you will run into errors.

I'd go so far as to say that the interface is not particularly relevant to the question. I'd expect it to work without that interface. The interface serves as a tool for users external to your package to define their own Product Service that can then be used within your application (as I'm sure you intended).

tl;dr;

I do believe it will always work as intended and this is not some crazy bug in SFDC that may be patched out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.