to Overview
Mai 21, 2016

Accessing Private Fields and Methods with XRayInterface

This posting is about accessing private fields and methods, by adopting a foreign interface to a given java class (not already implementing the given interface). Why? Yet, in my former posting about Repairing Legacy Code I mentioned the challenge of accessing hidden state (private fields) before and after method invocations.


Having access to private fields or method could be helpful in several scenarios:

  • for explicitly visualizing the contents of an object
  • for replacing this hidden state of the object with a mock object (injecting a mocked dependency)
  • for checking the contents of a hidden field that is used in another algorithm
  • for testing methods that are complex but should not be part of the public/protected/package private API

Yet, Java Reflection would be suitable to this problem - but not very elegant in my opinion. I think of a more elegant way of having objectoriented access to hidden state. My approach works as following:

Each visible state in Java is accessible through an interface. Consider a simple Java-Bean Name:

public class Name {

    private String firstName;
    private String lastName;
    
    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }
    
    public String getLastName() {
        return lastName;
    }
}

The inner state is not writable (after construction), but readable. So the implicit interface of this class would be:

interface NameReadable {
    String getFirstName();
    String getLastName();
}

Casting Name to NameReadable would not work. But Name needs not to be changed if implementing NameReadable. Now consider a class Name that is only partially readable:

public class Name {

    private String firstName;
    private String lastName;

    public Name(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }
}

The attribute lastName is not readable outside of Name. But it would be if Name was implementing NameReadable - or if Name would be convertable to NameReadable.

Though, how could this be done? The naive way would be simply to cast to NameReadable:

NameReadable read = (NameReadable) new Name("Foo","Bar"); //ClassCastException
System.out.println(read.getLastName());

This way would not work, but it is the approach we want to follow with XRayInterface. XRayInterface allows you to adopt an interface, in a very similar way as casting:

NameReadable read = XRayInterface.xray(new Name("Foo", "Bar"))
    .to(NameReadable.class);
System.out.println(read.getLastName()); // => Bar

This needs a bit more code (less if static imports are used). Now that we can read hidden state - how about writing hidden state. It works quite similar:

interface NameWritable {
    void setFirstName(String firstName);
    void setLastName(String lastName);
}

NameWritable write = XRayInterface.xray(new Name("Foo", "Bar"))
    .to(NameWritable.class);
write.setLastName("FooBar");

Strictly the XRayInterface-Method is designed in a way that each method defined in the target interface could be mapped in the intuitive way to the methods/fields of the underlying object.

XRayInterface yet also allows to do more than getting/setting hidden fields:

  • Access to private methods
  • Access to private construktors, static methods, static fields
  • Access to private fields that are “hidden” by property methods (there are annotations that control the mapping, so an interface method could be mapped eplicitly to a field or to a property method)