在什么情况下,Java的field.setAccessible(true)会失败?
我有一种情况,用户的代码在反射访问的字段上抛出IllegalAccessException
。在访问该字段之前,调用setAccessible(true)
。所以,在我看来,这种方法在默默地失败。在什么情况下,Java的field.setAccessible(true)会失败?
在什么情况下会发生这种情况?这可能与安全经理有关吗?
这是导致异常的代码片段:
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;
}
setAccessible
被记录为抛出SecurityException
。请注意,该文档给出了即使没有SecurityManager
存在,也会抛出SecurityException
的情况。当然,它也可能因异步异常而失败:Thread.stop
,NIO缓冲区相关异常或JVM错误。
该代码的真正问题(除了它使用反射)是有一个可以设置为部分初始化的字段。这会导致竞争条件(你有一个可变的静态,因此你需要担心线程(提示,避免可变的静态!))。在调用setAccessible
之前,另一个线程可能会在同一个Field
上调用getInt
。正如最初的提问者似乎已经发现的那样,它也不是特别安全。在静态初始化器中设置字段会更安全和更清晰。
这对我很有意义。谢谢。我不知道这是否是我所看到的问题,但似乎可能,因为我知道已知多个线程位于代码的这一部分。但即使这不是真正的问题,我应该改变我的代码。 – 2009-10-12 05:42:11
从Java自身documentation为setAccessible()
:如果标志是真实的,但
一个SecurityException提出的任何元素的可访问性的输入数组可能不会改变(例如,如果元素对象是Class类的Constructor对象)。如果发生这种SecurityException,则将对象的可访问性设置为标记数组元素直到(并排除)发生异常的元素;超出(并包括)发生异常的元素的元素的可访问性不变。
不幸的是他们不提关于IllegalAccessException.
任何它不应该是一个安全管理问题 - 你会得到一个SecurityException或子类。
代码levelField.getInt(*this*)
不看的权利...
你应该传递的MessageInfo
实例作为参数。
你是否在MessageInfo
这个课程中打过电话? (为什么?!?)或MessageInfo
的子类? (试图使一个超类行为的私人领域,如果它的受保护?是否MessageInfo
有getLevel()
方法吗?如果是这样,你可以调用super.getLevel()
获得的价值,而不是试图这样说的。)
如果不是MessageInfo
或子类,这就是你的问题 - 你有MessageInfo
类的level
字段,你试图从当前类中获取该字段的值。虽然这应该是抛出IllegalArgumentExeception
代替IllegalAccessException
...
如果它真的“IllegalAccessExeception” - 试图把一些日志记录if (levelField == null)
块内 - 确保它真正被exececuted。该字段是静态的 - 可能有其他实例或方法在其上设置值。
是的,这个类是MessageInfo类的一个子类,它是我正在使用的框架的一部分。所以,level字段是MessageInfo的一个封装保护字段,没有getter,所以它不能被我的子类访问。 此代码适用于许多许多用户,但不是这个特定的代码。所以,我想知道这个特定人员的设置是否可能存在一些特殊情况,使得通话在这里失败。这导致我认为它可能是一个安全管理器的事情,但我想知道是否还有别的东西。 – 2009-10-11 16:52:16
也许这个用户在类路径上有这个框架的更新/旧版本? MessageInfo.level不存在或名称不同?附: - 它是什么框架?可能帮助排除这个... – Nate 2009-10-11 22:43:53
也许,但不太可能。我所描述的框架是Eclipse的JDT。这是我们至少3.3以来一直在使用的代码(在我开始编写项目之前)。我已经测试过Eclipse 3.5.1。如汤姆在接受的答案中所述,我相信这可能是一个线程问题。 – 2009-10-12 05:44:21
打印出异常消息和stacktrace会有帮助。 – NawaMan 2009-10-11 04:03:35