Making Privates Public

Disclaimer: This code is not for the faint-hearted and should not be used without very good reason (in our case, an external library not giving us access to a fair property of a certain class). Tested only on Java 5.

public static Object getPrivateFieldValue(Object anObject, String fieldName)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throws NoSuchFieldException, IllegalAccessException {<br />&nbsp;&nbsp;&nbsp;&nbsp;Class theObjectClass = anObject.getClass();<br />&nbsp;&nbsp;&nbsp;&nbsp;Field field = theObjectClass.getDeclaredField(fieldName);<br />&nbsp;&nbsp;&nbsp;&nbsp;field.setAccessible(true); // make it available outside of class or package<br />&nbsp;&nbsp;&nbsp;&nbsp;return field.get(anObject);<br />}

Sometimes it’s scary how it can be just that easy…

8 Replies to “Making Privates Public”

  1. You’re bound to trip on a security exception sooner or later if you’re using that on a sandbox, though – that means no unsigned applets or JWS apps would work with this code if you don’t fiddle with the security policy files.

  2. I have used similar for methods to test some third party libs that were detestable.

    A programmer’s must do what a programmer’s must do. Especially when testing.

  3. Agreed that this technique may not work in a sandbox enviroment without setting up the correct security permissions, but for the purposes of what we needed it for (testing) it was useful. To give it a little more context, we found that some code we had (using Hibernate) left some cursors open far too long, so we wanted a way to assert that at the end of a certain block of code, the existing session no longer had any result sets left to close. We wanted a way of accessing a certain property (resultSetsToClose) that was private and asserting that it should be empty.

    On a side note, be wary of code that looks like this:

    Iterator results = someHibernateQuery.iterate();
    return results.hasNext();
    // not calling results.next() leaves the resultSet open until session.close() is called

  4. Um…. you know that Hibernate is doing the same thing to private accessors & mutators, right? 🙂

    The visibility modifiers are just hints to the compiler; there are ways to get around it, and there _should_ be ways to get around it. This mechanism is also used by debuggers to show you the state of objects, BTW.

    In general, mock objects & IoC would work better here; pass the session in, assert that it was closed. Done.

  5. Robert, I’ve never drilled into the source code of Hibernate or any debugger for that matter, but I would guess that any framework/tool/project that depends on heavy reflection might use this sort of mechanism.

    Also, I’m not sure that if any (existing) mock or IoC would really give us the same result here. The point of the code was not to ensure the session was closed (other tests/constraints check for that), but to ensure that any result sets within a session get fully consumed (otherwise our Oracle DB open cursors shoot up rapidly, and we know from experience what a bad thing that can be).

    It was also nice to see how succinct the code block really was when we needed it. Thanks for your comments though. Good to know all of this detail.

  6. Using IoC and mocks allows you to test any interactions you care to name; a test that says “hey, hasNext() was called, but next() wasn’t” isn’t hard to write. The question is working out which interactions you want to look for, and that’s where experience comes in. (“Experience – what you get just after you needed it”)

  7. Robert, I’ve found IoC and mocks are useful mainly when the interaction between several classes is well defined and forms part of their contract. I believe that the behaviour we observed was not intended to be part of this class’s contract and happened to be a side-effect of the way the class was implemented.

    Sure we could have written a failing test using IoC and Mocks for the solution we came up with (guaranteeing next() was called) but I’m not a big fan of leaving tests that only test for the solution we selected (perhaps there was another way?). In this particular circumstance I don’t mind adding a test that uses the real class (because it is implementation specific), and it better leaves others the reason why our solution had to be implemented.

    Oh, and Diamond Geeza, yes very old, but sometimes you just remind yourself how good something old can be.

Comments are closed.