3

We have a following setup:

  • a managed package pkg_a which provides a global virtual class Cls_A to be extended

  • a managed package pkg_b which contains a global class Cls_B that extends pkg_a.Cls_A

  • a static method in pkg_a's class which tries to retrieve a Type given its full name:

    public static Type findType(String fullName) {
        if (String.isBlank(fullName)) {
            return null;
        }
    
        Type foundType = Type.forName(fullName);
        if (foundType == null) {
            // now try to find it locally without package prefix
            foundType = Type.forName('', fullName);
    
            // try with package prefix
            if (foundType == null && fullName.contains('.')) {
                List<String> splitStr = fullName.split('\\.', 2);
    
                String namespace = splitStr[0];
                String className = splitStr[1];
    
                foundType = Type.forName(namespace, className);
            }
        }
        return foundType;
    }
    

When this method is called within pkg_a context:

    Type t = MyClass.findType('pkg_b.Cls_B');

it returns null for some reason. Does anyone know what are the possible reasons for this? Why wouldn't one managed package see a global class from another managed package, especially if this other class is extending package's own class?

What was checked so far:

  • pkg_b.Cls_B is set to depend on the latest version of pkg_a

  • Cls_B methods are public

  • user running the pkg_a process which calls the findType() method has a System Adminstrator profile with access to all classes and packages, so it's unlikely that it's a permissions problem

  • the most puzzling bit: this behaviour was noticed on an Enterprise edition org; on dev orgs everything works correctly

8
  • What happens if you try to call it explicitly without type.forName() ? Are you able to instantiate the class ? Nov 1, 2016 at 16:36
  • 1
    I've tried to instantiate it directly from Dev console, worked without a problem. Nov 1, 2016 at 16:47
  • You may have to add the namespace in the type.forname instead of using '' since the class from one package is in a different namespace that the local one the dev console uses
    – Eric
    Nov 1, 2016 at 18:18
  • or maybe call it like that since it is a string: Type t = MyClass.findType('pkg_b__Cls_B'); Nov 2, 2016 at 15:32
  • @Eric - Do you mean something like Type.forName('pkg_b', 'pkg_b.Cls_B')? If you check the findType() method, it already accounts for the namespace within the class name string passed to it. Nov 3, 2016 at 9:03

1 Answer 1

4

Well, other colleagues have run into the same issue, and found the underlying reason.

After pkg_a was installed, each package that was installed after it added a version dependency to pkg_a's classes, e.g. after pkg_b v1.23 was installed, pkg_a's classes had pkg_b v1.23 dependency added to them. After the packages were updated, however, all classes in pkg_a that weren't modified/updated didn't have their dependencies updated either. So, after pkg_b was updated to v1.25, unmodified classes from pkg_a still had a dependency on pkg_b v1.23. Cls_B was introduced in v1.25, so an unmodified class from pkg_a couldn't see it since it still had a dependency on v1.23. Changing the dependency version manually while logged on as a Subscriber didn't work, SFDC returned an error "Only code in local namespace can be changed" (or a similar message in the same vein).

The problem was solved by modifying the class in pkg_a that tries to reference classes from other packages - an empty line or two were added - and creating a patch release which was installed on the target org. This caused SFDC to see the affected class as modified, recompiling it and updating the package dependencies on it.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .