Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Under what situations will Java's field.setAccessible(true) fail?

I have a situation where a user's code is throwing an IllegalAccessException on a field accessed by reflection. Just before accessing the field, setAccessible(true) is called. So, it would seem to me that this method is silently failing.

Under what situations would this happen? Could this have something to do with a security manager?

Here is the code snippet that is causing the exception:

private static Field levelField;
public int getLevel() {
    try {
        if (levelField == null) {
            levelField = MessageInfo.class.getDeclaredField("level");
            levelField.setAccessible(true);
        }
        return levelField.getInt(this);  // <-- IllegalAccessException thrown here
    } catch (Exception e) {
         handleException(e);
    }
    return ICompilationUnit.NO_AST;
}
like image 393
Andrew Eisenberg Avatar asked Oct 11 '09 03:10

Andrew Eisenberg


2 Answers

It shouldn't be a security manager issue - you'd get a SecurityException or subclass.

The code levelField.getInt(*this*) doesn't look right...

You should be passing an instance of MessageInfo as the parameter.

Are you calling this from within the MessageInfo class? (why?!?) or a subclass of MessageInfo? (Trying to make a private field of a superclass act as if it's protected? Does MessageInfo have a getLevel() method? If so, you could call super.getLevel() to get the value instead of attempting it this way.)

If it's not MessageInfo or a subclass, that's your problem - you have the level field of the MessageInfo class and you're attempting to get the value of that field off the current class. Though this should be throwing an IllegalArgumentExeception instead of IllegalAccessException...

If it's really 'IllegalAccessExeception' - try putting some logging inside that if (levelField == null) block - make sure it's really being exececuted. The field is static - there may be some other instance or method setting a value on it.

like image 105
Nate Avatar answered Nov 07 '22 05:11

Nate


setAccessible is documented to throw a SecurityException. Note that the documentation gives cases where SecurityException will be thrown even if there is no SecurityManager present. Of course it may also fail due to an asynchronous exception: Thread.stop, NIO buffer related exception or a JVM error.

The real problem with this code (other than that it uses reflection) is that there is a field that can be set to be partially initialised. This causes a race condition (you have a mutable static, therefore you need to worry about threads (hint, avoid mutable statics!)). Another thread may call getInt on the same Field before setAccessible is called. And as the original questioner appears to have found out, it isn't exception safe either. It would be much safer and clearer to set up the field in a static initialiser.

like image 38
Tom Hawtin - tackline Avatar answered Nov 07 '22 05:11

Tom Hawtin - tackline