Friends for Java

Often (while working on OpenJDK’s code for example) I come across code where a class in one package needs to access private or package private stuff in another package, but that stuff can’t be made public. For example, an implementation class sometimes needs access to some API class, but we don’t want to open up the API class generally. Also, the implementation stuff cannot easily be moved to the API package.

The first instinct seems to be to use reflection to solve that problem. I’ve also seen some cases where JNI is used to access private stuff (/me eyes to the Java2D and AWT teams..). However, these approaches have their own disadvantages:

  • Not compile-time safe. If the accessed method changes, the compiler won’t block you. You also get no type checking.
  • You have to be careful about security manager issues, if your code needs to run w/ security manager.
  • Performance could be worse, depending on the VM.

Other languages (like C++) have the friend keyword, which allows to explicitly grant access to private code to another class or function (the friend). This can be quite useful, and I want to show how to do something similar in Java (also inspired by some code in OpenJDK btw).

Let’s assume the following classes:

package api;
public class A {
  void doSecretSauce() {
    // Doing secret sauce here.
  }
}
package impl;
public class B {
  void needsSecretSauce() {
    // TODO: How to do secret sauce here??
  }
}

Now, how can needsSecretSauce() access doSecretSauce() ? Basically, we have to create a friend relationship between the two classes. Let’s introduce an interface into the impl package:

package impl;
public interface AccessA {
  void doSecretSauce(A a);
}

This interface allows B to access doSecretSauce() in A, if A can provide us an implementation of it. Now we need a place where A can store such an implementation:

package impl;
public class Friends {
  private AccessA accessA;
  public void setAccessA(AccessA aa) {
    accessA = aa;
  }
  AccessA getAccessA() {
    return accessA;
  }
}

Note that the setter is public, so that A can access it, but the getter is package private, so only classes in impl can actually use it. We also need a getInstance() method to get a singleton instance of this class. I assume you know how to implement that ;-). Now we can change the A class to ‘export’ its friend relationship to the impl package:

package api;
import impl.Friend;
import impl.AccessA;

public class A {
  static {
    Friend.getInstance().setAccessA(new AccessAImpl());
  }

  private static class AccessAImpl implements AccessA {
    public void doSecretSauce(A a) {
      a.doSecretSauce();
    }
  }

  void doSecretSauce() {
    // Doing secret sauce here.
  }
}

And finally let B do some secret sauce:

package impl;
public class B {
  void needsSecretSauce() {
    Friends.getAccessA().doSecretSauce(a); // a initialized elsewhere.
  }
}

This solution now is compile time safe, doesn’t raise any security manager concerns, shows best possible performance and is reasonable secure. In OpenJDK there’s the sun.misc.SharedSecret class which basically does what our ‘Friends’ class here does for java.lang and some other packages.

Advertisements

8 Responses to Friends for Java

  1. Dmitri Trembovetski says:

    This sounds very much like pattern used here for setting the surfaceManager: http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/50c67678b0d1/src/share/classes/java/awt/Image.java

    Dmitri

  2. Roman Kennke says:

    Dmitri: exactly. I wish that all AWT and Java2D code was like this 😉

  3. Yeah I wrote about this too, a while back:

    http://blog.fuseyism.com/index.php/2008/05/26/sharing-secrets/

    It’s safer than some other solutions, but I’m still not sure how safe it is i.e. what stops some other user class accessing the same implementation? For a real friend relationship, we need to be able to promote our package (say sun.awt) to a trusted status with respect to java.awt.

  4. Roman Kennke says:

    Depending of the use-case, the pattern can be optimized a bit by putting the interface AccessA and the class Friends together into an abstract class:

    public abstract class Friends {
    public abstract void doSecretSauce(A a);

    private static AccessA accessA;
    public static void setAccessA(AccessA aa) {
    accessA = aa;
    }
    static AccessA getAccessA() {
    return accessA;
    }

    }

    This makes it a bit less verbose.

  5. James Hunt says:

    Using an abstract class instead of an interface has the additional benefit, that access to the friend class can be limited to the two packages involved.

    package api;

    import impl.FriendA;

    /**
    * Accessor implements the friendship
    */
    public class A
    {
    static
    {
    AccessorA accessor = new AccessorA();
    accessor.export();
    }

    private static class AccessorA extends FriendA
    {
    @Override
    protected void doSecretSauce(A a)
    {
    a.doSecretSauce();
    }

    void export()
    {
    FriendA.setAccessorA(AccessorA.this);
    }
    }

    void doSecretSauce()
    {
    // Doing secret sauce here.
    }
    }

    package impl;

    import api.A;

    /**
    * Defines the Friendship
    */
    public abstract class FriendA
    {
    private static FriendA friend_;

    protected abstract void doSecretSauce(A a);

    protected static void setAccessorA(FriendA friend)
    {
    friend_ = friend;
    }

    static FriendA getAccessorA()
    {
    return friend_;
    }
    }

  6. Interesting. IMO, it would be much easier to follow your logic if you simply included the entire code and then did the code discussion afterwards.

    What’s the deal of the singleton – couldn’t just the Friend getter and setter be static? What prevents anyone from setting a random EvilAccessAImpl that does something completely different than simply proxy the package private method invocation?

  7. @James: My Evil class can extend FriendA too?

    package impl;

    import api.A;

    public class ImplTest {
    public void doTest() {
    A a = new A();
    FriendA.getAccessorA().doSecretSauce(a);
    }
    }

    import impl.FriendA;
    import impl.ImplTest;
    import api.A;

    public class Evil {
    public static void main(String[] args) {
    ImplTest test = new ImplTest();
    test.doTest();
    new EvilAccessor().export();
    test.doTest();
    }

    private static class EvilAccessor extends FriendA {
    @Override
    protected void doSecretSauce(A a) {
    System.out.println(“Evil!”);
    }

    void export() {
    FriendA.setAccessorA(this);
    }
    }
    }

    Here’s an attempt towards fixing the security, can this work? The idea is that both classes must “handshake” by use of a secret object:
    http://tech.stolsvik.com/2009/03/friends-for-java.html

  8. James Hunt says:

    If you are really paranoid, you could check the package name of the class of the object in the set methods with a guard like “friend.getClass().getPackage().equals(A.class.getPackage())” to make sure the Friend comes from the same package. This is simpler than passing a secret.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: