Java 反射:枚举是公共的,方法也是公共的,那么为什么会出现IlegalAccessException呢?
请耐心等待,我会尽可能多地提供信息 我的代码中随机出现以下异常,但并非总是如此:Java 反射:枚举是公共的,方法也是公共的,那么为什么会出现IlegalAccessException呢?,java,reflection,enums,mybatis,illegalaccessexception,Java,Reflection,Enums,Mybatis,Illegalaccessexception,请耐心等待,我会尽可能多地提供信息 我的代码中随机出现以下异常,但并非总是如此: ERROR CACHE-SELECT 2015-08-20 11:19:00,822 nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'table.selectQuerySuffix'. Cause: org.apache.ibatis.ognl.OgnlException: se
ERROR CACHE-SELECT 2015-08-20 11:19:00,822 nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'table.selectQuerySuffix'. Cause: org.apache.ibatis.ognl.OgnlException: selectQuerySuffix [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class com.dclear.cmn.core.cache.CacheEnum$4 with modifiers "public"] -
定义的枚举如下所示:
public enum CacheEnum {
TABLE_NAME() {
@Override
public String getSelectQuerySuffix() {
return "";
}
};
private CacheEnum() {
//some assignment
}
public enum Schema {
//SCHEMAS DEFINED
}
public enum SchemaName {
// NAMES
}
public String getSelectQuerySuffix() {
return "";
}
public enum ColumnEnum {
//SOME VALUES
ColumnEnum() {
}
}
public enum CacheTableSequence {
//SQs
}
}
“table.selectQuerySuffix”在MyBatis文件中定义,用于放置查询后缀。在运行时,它作为“”传递(请参阅重写的方法getSelectQuerySuffix()
这个问题并不总是会出现……我已经读到了
当应用程序尝试调用时,将引发IllegalAccessException
反射式创建实例(而不是数组)、设置或获取
字段,或调用方法,但当前执行的方法不
有权访问指定类、字段、方法或的定义
构造器
没有用户定义的类装入器
但是,如果问题是因为构造函数CacheEnum是私有的,为什么它不总是出现?如果不是,那么背后的问题是什么?我在这里遗漏了什么?当我们定义如下枚举时:
public enum EnumTest {
ONE, TWO() {
@Override public String hello() {
return "World";
}
};
public String hello() {
return "Hello";
}
}
Java for TWO创建了一个匿名类。我对其进行了分解,结果如下:
class snippet.EnumTest$1 extends snippet.EnumTest {
snippet.EnumTest$1(java.lang.String, int);
public java.lang.String hello();
}
因此,用于TWO
的类是受包保护的,当我们实际访问TWO的类时,反射不起作用。例如,获取两个枚举对象并获取其类。我怀疑你的情况就是这样。对于方法未被重写的所有情况,它都在工作;对于方法被重写的情况,它应该抛出异常
我写了下面的测试来检查它
public class EmumReflect {
public static void main(String[] args) throws Exception {
f1();
f2();
}
public static void f1() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
InvocationTargetException {
Class<?> forName = Class.forName("snippet.EnumTest");
Object fOne = forName.getField("ONE").get(null);
Object fTwo = forName.getField("TWO").get(null);
Method method = forName.getMethod("hello");
System.out.println(method.invoke(fOne));
System.out.println(method.invoke(fTwo));
}
public static void f2() throws ClassNotFoundException, IllegalAccessException, NoSuchFieldException, NoSuchMethodException,
InvocationTargetException {
Class<?> forNamex = Class.forName("snippet.EnumTest");
Object fTwo = forNamex.getField("TWO").get(null);
Class<?> forName = fTwo.getClass();
Method method = forName.getMethod("hello");
System.out.println(method.invoke(fTwo));
}
}
公共类EmumReflect{
公共静态void main(字符串[]args)引发异常{
f1();
f2();
}
public static void f1()抛出ClassNotFoundException、IllegalAccessException、NoSuchFieldException、NoSuchMethodException、,
调用目标异常{
Class-forName=Class.forName(“snippet.EnumTest”);
Object fOne=forName.getField(“一”).get(null);
对象fTwo=forName.getField(“两”).get(null);
Method=forName.getMethod(“hello”);
System.out.println(method.invoke(fOne));
System.out.println(method.invoke(fTwo));
}
public static void f2()抛出ClassNotFoundException、IllegalAccessException、NoSuchFieldException、NoSuchMethodException、,
调用目标异常{
类forNamex=Class.forName(“snippet.EnumTest”);
对象fTwo=forNamex.getField(“两”).get(null);
类forName=fTwo.getClass();
Method=forName.getMethod(“hello”);
System.out.println(method.invoke(fTwo));
}
}
如果将类文件EnumTest和EnumReflect保留在同一个包中,则不会出现任何异常。但是,如果将它们保存在不同的包中,f2()会抛出与您得到的相同的异常。类名“com.dclear.cmn.core.cache.CacheEnum$4”意味着您的枚举具有匿名类。是否可以显示完整的CacheEnum源代码?@dish我猜您的类装入器有问题。您正在使用的平台/框架是否定义了自己的类加载器?com.dclear.cmn.core.cache.CacheEnum$4
应该是指CacheEnum中的第四个匿名类。假设所有枚举值都像DD\u FEED\u FIELD\u NF\u MAP
,很可能是第四个条目。您能发布它吗?@dish每当您从枚举重写一个方法时,编译器应该为该元素创建一个匿名类并分配它。我在谷歌上搜索了一下,可以在apache.ibatis中找到一些对javaassist和类加载器的引用。我仍然觉得这是一些类装入器问题。(我当然可能错了,我对ibatis一无所知)。如果可以,只要在发生这种情况的任何地方打印this.getClass().getClassLoader()。至少我们可以看到是否正在使用多个类加载器。这似乎是一个非常好的捕获,我现在将尝试研究更多关于这一点,以确保在发布此修复之前!谢谢。不过,你总是有例外吗@马尔韦。从f2()
。检查是否仅针对重写getSelectQuerySuffix
方法的枚举获得异常。框架中的代码路径可能是这样的:有时这些枚举可能会通过(请参见f1()
),而仅在其他情况下失败。如果您在访问未覆盖的其他枚举时遇到异常,则getSelectQuerySuffix
-这不是问题所在。出色的分析