Java Programming Tip: Using Reflection to Call Any Method (Even a Private One!)
Many of us have encountered the following situation: You are coding a tricky algorithm and discover that a very useful method for doing what you're doing already exists. Alas, it's private, or perhaps "package" visible (in a package that you're not in!) and you have no way of accessing it. You end up duplicating the code yourself, perhaps grumbling under your breath about how the other developer should have made the useful method public. I have some good news for you. By using Java's built-in reflection API, you can actually call any method you want under most circumstances!
How? It's easy. It all comes down to the setAccessible(boolean) method of the AccessibleObject class, of which Method is a subclass. Let's take a look at some example code. First, a class that contains our "target method", the one we want to call but can't access:
public class Foo { private boolean same(int x, int y) {
return ( x == y );
} }
Here's a class that uses reflection and "setAccessible" to call the method (NOTE: uses Java 5 language features):
public class Bar implements Runnable { static public void main(String... args) {
new Bar().run();
} public void run() {
try {
Foo foo = new Foo();
Method targetMethod = foo.getClass().getDeclaredMethod( "same", int.class, int.class ); // This is the magic line
targetMethod.setAccessible(true); Boolean result = (Boolean)targetMethod.invoke( foo, 4, 4 );
System.out.println( result );
}
catch (Exception e) {
e.printStackTrace();
}
}}
Pretty easy, isn't it? You can also call static methods using this approach. Let's imagine that the method in our Foo class had been static. In that case, here's what we would have done instead:
public class Bar implements Runnable { static public void main(String... args) {
new Bar().run();
} public void run() {
try {
Method targetMethod = Foo.class.getDeclaredMethod( "same", int.class, int.class ); // This is the magic line
targetMethod.setAccessible(true); Boolean result = (Boolean)targetMethod.invoke( Foo.class, 4, 4 );
System.out.println( result );
}
catch (Exception e) {
e.printStackTrace();
}
}}
Notice that the difference is simply that we cannot use an instance of Foo to get the class object, and that during the invocation of the method we use the class itself as the first parameter, rather than an instance.
This technique isn't foolproof. Every time you call "setAccessible", the installed security manager (if there is one) is given an opportunity to block the call. However, I've not yet encountered a situation in which this was actually blocked. That said, just because you can do something doesn't mean you should, so be sure to use this approach with caution, and certainly only when you absolutely must! After all, it is fundamentally "breaking the rules" that are being expressed in the code itself.
