来源:http://h5ip.cn/aJgJ
### Error querying database. Cause: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'list != null and list.size() > 0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
### Cause: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'list != null and list.size() > 0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23) org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:107)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:98)
at cn.com.shaobingmm.MybatisBugTest$2.run(MybatisBugTest.java:88)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.ibatis.builder.BuilderException: Error evaluating expression 'list != null and list.size() > 0'. Cause: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java
at:47)
at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:29)
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:30)
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:29)
at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:51)
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:29)
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:37)
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:275)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:79)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:104)
... 3 more
Caused by: org.apache.ibatis.ognl.MethodFailedException: Method "size" failed for object [1] [java.lang.IllegalAccessException: Class org.apache.ibatis.ognl.OgnlRuntime can not access a member of class java.util.Collections$SingletonList with modifiers "public"]
at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:837)
at org.apache.ibatis.ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:61)
at org.apache.ibatis.ognl.OgnlRuntime.callMethod(OgnlRuntime.java:860)
at org.apache.ibatis.ognl.ASTMethod.getValueBody(ASTMethod.java:73)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:109)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
at org.apache.ibatis.ognl.ASTGreater.getValueBody(ASTGreater.java:49)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:56)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:170)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:210)
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:333)
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:413)
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:395)
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:45)
... 12 more
多线程并发环境下的压测代码
异常信息表明OgnlRuntime类不能够访问java.util.Collections的私有成员SingletonList。查看源代码发现能够抛出MethodFailedException异常可以锁定在invokeMethod方法内部。
public static Object callAppropriateMethod(OgnlContext context, Object source, Object target, String methodName, String propertyName, List methods, Object[] args) throws MethodFailedException {
Object reason = null;
Object[] actualArgs = objectArrayPool.create(args.length);
try {
Method e = getAppropriateMethod(context, source, target, methodName, propertyName, methods, args, actualArgs);
if(e == null || !isMethodAccessible(context, source, e, propertyName)) {
StringBuffer buffer = new StringBuffer();
if(args != null) {
int i = 0;
for(int ilast = args.length - 1; i <= ilast; ++i) {
Object arg = args[i];
buffer.append(arg == null?NULL_STRING:arg.getClass().getName());
if(i < ilast) {
buffer.append(", ");
}
}
}
throw new NoSuchMethodException(methodName + "(" + buffer + ")");
}
Object var14 = invokeMethod(target, e, actualArgs);
return var14;
} catch (NoSuchMethodException var21) {
reason = var21;
} catch (IllegalAccessException var22) {
reason = var22;
} catch (InvocationTargetException var23) {
reason = var23.getTargetException();
} finally {
objectArrayPool.recycle(actualArgs);
}
throw new MethodFailedException(source, methodName, (Throwable)reason);
}
public static Object invokeMethod(Object target, Method method, Object[] argsArray) throws InvocationTargetException, IllegalAccessException {
boolean wasAccessible = true;
if(securityManager != null) {
try {
securityManager.checkPermission(getPermission(method));
} catch (SecurityException var6) {
throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
}
}
if((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) && !(wasAccessible = method.isAccessible())) {
method.setAccessible(true); (1)
}
Object result = method.invoke(target, argsArray); (3)
if(!wasAccessible) {
method.setAccessible(false); (2)
}
return result;
}
问题出现在method实际上是一个共享变量,也就是例子中的
public int java.util.Collections$SingletonList.size()
public static Object invokeMethod(Object target, Method method, Object[] argsArray) throws InvocationTargetException, IllegalAccessException {
boolean syncInvoke = false;
boolean checkPermission = false;
int mHash = method.hashCode();
synchronized(method) {
if(_methodAccessCache.get(Integer.valueOf(mHash)) == null || _methodAccessCache.get(Integer.valueOf(mHash)) == Boolean.TRUE) {
syncInvoke = true;
}
if(_securityManager != null && _methodPermCache.get(Integer.valueOf(mHash)) == null || _methodPermCache.get(Integer.valueOf(mHash)) == Boolean.FALSE) {
checkPermission = true;
}
}
boolean wasAccessible = true;
Object result;
if(syncInvoke) {
synchronized(method) {
if(checkPermission) {
try {
_securityManager.checkPermission(getPermission(method));
_methodPermCache.put(Integer.valueOf(mHash), Boolean.TRUE);
} catch (SecurityException var12) {
_methodPermCache.put(Integer.valueOf(mHash), Boolean.FALSE);
throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
}
}
if(Modifier.isPublic(method.getModifiers()) && Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
_methodAccessCache.put(Integer.valueOf(mHash), Boolean.FALSE);
} else if(!(wasAccessible = method.isAccessible())) {
method.setAccessible(true);
_methodAccessCache.put(Integer.valueOf(mHash), Boolean.TRUE);
} else {
_methodAccessCache.put(Integer.valueOf(mHash), Boolean.FALSE);
}
result = method.invoke(target, argsArray);
if(!wasAccessible) {
method.setAccessible(false);
}
}
} else {
if(checkPermission) {
try {
_securityManager.checkPermission(getPermission(method));
_methodPermCache.put(Integer.valueOf(mHash), Boolean.TRUE);
} catch (SecurityException var11) {
_methodPermCache.put(Integer.valueOf(mHash), Boolean.FALSE);
throw new IllegalAccessException("Method [" + method + "] cannot be accessed.");
}
}
result = method.invoke(target, argsArray);
}
return result;
}