views:

229

answers:

4

In both Java and C# it is possible to invoke a private method via reflection (as shown below).

  • Why is this allowed?
  • What are the ramifications of doing this?
  • Should it be taken away in a future version of the language?
  • Do other languages/platforms allow this?If I have this class in both Java and C#

Here is the example

public class Foo
{
    private void say() { WriteToConsoleMethod("Hello reflected world"); }
}

where WriteToConsole() is language specific, then I can run the following to call the private say() method:

C#

Foo f = new Foo();
var fooType = f.GetType();
var mi = fooType.GetMethod("say", BindingFlags.NonPublic | BindingFlags.Instance);
mi.Invoke(f, null);

Java

Foo f = new Foo();
Method method = f.getClass().getDeclaredMethod("say", null);
method.setAccessible(true);
method.invoke(f, null);

As you can see, it is not obvious, but it's not difficult either.

+4  A: 

This is allowed because access restrictions are not meant to be a security measure.

It is kind of like putting locks on your house - they are a deterrent but they do nothing against someone who wants to use a battering ram to break down the door.

Andrew Hare
Access restrictions are a primary security measure when running mobile code.
Tom Hawtin - tackline
@Tom - which is why in those environments there will almost certainly be a security manager present that will reject the operation. See, for example, docs for setAccessible in http://java.sun.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html.
Andrzej Doyle
I'd say it's more like putting a *sign* on a window saying "please use the door" - it maps better to the idea of publically accessible interfaces vs. implementation details. And then running with a security manager is like putting a bouncer with a big stick in front of the sign to make sure people follow it... :-)
Andrzej Doyle
+16  A: 

In both Java and .NET, this is only allowed if you have sufficient permissions. Code that you run directly from the command line is (usually) operating in "full trust" mode. If you try doing the same thing in more restrictive environments, it will fail. Access control is more about encapsulation than security though. If you're operating at full trust, you've probably got enough access to launch native methods to poke around memory directly anyway...

  • Why is it allowed? Sometimes it can be handy. It should be treated with care, but it can be useful.

  • What are the ramifications? Your code becomes fragile; you're interacting with a type in a way it doesn't expect.

  • Should it be taken away in a future version of the language? It's a platform feature rather than a language feature in the first place, but no I don't think it should be removed.

  • Do other languages/platforms allow this? I'm not sure... I wouldn't be surprised though.

Jon Skeet
"Sometimes it can be handy" - I have found occasion where I've used reflection to unit test private methods. One might argue that, being encapsulated, it should be tested through provided interfaces and public methods. But sometimes these private methods encapsulate a small bit of complex logic with some interesting edge cases where direct unit tests really improve development. So yes, can be handy sometimes!
Matt
+1  A: 

If for some reason you need to make sure that inappropriate callers cannot call a certain method (like if there is some kind of password/security risk), have a look at Code Access Security in .net. There is a way to tell the runtime to only allow a method to be called by callers who have a specific Authenticode signature.

JMarsch
A: 

The private/protected/public model of C++ became popular because C++ became popular, not because it was a great idea.

There are a lot of libraries out there that set methods to private that really should not have; some programmers will set nearly everything to private without understanding why you would do so, and some IDEs create scaffolding code with private set when it probably shouldn't be.

The result is that a lot of libraries have good, useful ideas, but have mistakes somewhere in their methods, and often those methods are marked private. The problem with private/protected/public and the normal constraints that come along with them is that you can't plan for everyone else's future use of your code. Even if you somehow managed to write bug-free code (which you won't), popular libraries will still find future uses you didn't anticipate. The author can't possibly determine which methods and variables will need to be accessed, overridden, tweaked etc for every single future use at the time they write it. It's just too much responsibility.

So this reflection trick you found breaks this model, but the truth is it should probably be EASIER to break, not more difficult. I would not look at this as a bug.

In fact in .Net you can use Reflector to take this approach even farther and avoid the real-time reflection calls in your code, to avoid the performance hit incurred when you find buggy code marked private. If you do so, try to avoid private declarations in the new code you write, to be nice to the next author who leverages your work.

Chris Moschini