Keyed Access Pattern
Developer's Cave February 9th. 2009, 7:32amIn a previous article, I described a Concealed Controller Pattern, which allows Java classes to be packaged separately, while maintaining access control to certain sensitive methods. In today’s article, I discuss the shortcomings of Java’s package capabilities and present a simple pattern (the Keyed Access Pattern) for overcoming one case.
Motivation: The Java Programming Language allows classes within the same package to access one another’s package-protected methods. This allows related classes to have special access, without exposing those methods publicly. Oftentimes it is desirable to further group related classes into a package hirarchy.
Unfortunately, the Java Programming Language does not have any actual notion of a sub-package; all packages define a unique namespace, regardless of the implied naming hierarchy. For example, a package named parent.child is in no way a sub-package of the parent package; they are two entirely different packages, according to the Java Language Specification. Under that rule, Java cannot offer any special-case class or method accessors for sub-packages.
Suppose your parent.child classes have methods that should only be accessible by parent classes, such as Child.give(Candy). In Java, this method must be public for any class outside parent.child to access.
One solution is to create a base class in the parent package, which the parent.child.Child class extends. However, for the purposes of this example, assume that inheritance is not a viable option for the Child class.
Keyed Access Pattern: To avoid strangers giving a Child candy, require a Permission (key) object be passed in: Child.give(Permission,Candy). Permission has a package-protected constructor in the parent package. This enforces that only a parent-packaged class can give candy to a Child (so long as no parent gives out its Permission). The child must always validate that the permission is non-null. Through this pattern, the Child class can be packaged separate from parents, and still provide a public method for receiving candy, which only parents can access.
Pseudocode:
package parent; public final class Permission { Permission() { } // package-protected constructor } package parent; public final class Parent { private final Permission key = new Permission(); public Parent() { } // although the child's candy method is public, // only a parent can construct a key for access; // the following public method can enforce logic // required to safely give a child candy public void offer(Candy candy) { if (safeToEat(candy)) { child.give(key, candy); } } } package parent.child; public final class Child { public Child() { } public void give(Permission p, Candy c) { if (p != null) { eat(c); } } }
Acute practitioners of software design will recognize that this pattern produces a circular package dependency. That is, in this example, the parent.Parent depends on parent.child.Child and parent.child.Child depends on parent.Permission. Thus, the parent and child packages each depend on classes from one another. Java itself has no problem with this, but it is generally viewed as poor programming practice. Although I tend to be rather strict about such things, I consider this case to be acceptable, because it is necessary to enforce a condition not provided by the language: cross-package protected access.
In practice, I only employ this pattern in simple conditions. Breaking down a large package into many (pseudo-)sub-packages would require littering the child class methods with key objects, to enforce parent-only access. The most elegant solution would be an addition to the Java Language Specification, allowing for true hierarchical namespaces, but that is a discussion for another day…













February 9th, 2009 at 10:47 am
I believe “modules” are under discussion for the next version of Java. You might find a better solution using annotations, too.
I would be interested in knowing why you feel this sort of control is necessary. Yes, it seems you have a solution to the problem here, but I would hardly call it a reasonable solution. Personally, I believe access restrictions are useful primarily to make it easier for another developer to know what is available in a class. What this proposes makes things pretty convoluted.
And besides, we can take one of three philosophies about code protection:
1. We can assume that another developer is incompetent and will mess up the application.
2. We can assume that another developer is malicious.
3. We can assume the other developer is competent.
Sure, there are certainly cases where 1 and 2 are legitimate problems, but I feel that maybe we shouldn’t allow 1’s and 2’s to access our code at all. I just seems that being overly protective is, like nearly all security measures, simply punishing the honest people. In this case, yourself.
February 9th, 2009 at 11:45 am
All good points. I see modules as improving the Java application deployment process, but not providing any new language-level API improvements. Annotations are closer to the code, but also do not provide any compile-time API restrictions.
The goal of this pattern is not security, but integrity of design. I agree that this is not a reasonable solution. The real solution is to either package all such classes together or separate them and live with public methods (or write blog articles discussing improvements to the platform).
I feel that the spirit of Java has always been correctness over convenience, which then feeds back on itself as the correctness becomes ease of development. I’m a big believer in RTFM, but opening up a bunch of public methods can make a code base hard to use and maintain.
Overall, I prefer to have a strictly defined API, but you’re absolutely correct that it can get out of hand. Mainly, I think I just don’t like convenience.