mybatis-3: Getting "NoSuchPropertyException" Randomly
Hi,
We are using mybatis-3.3.0. Recently we got one strange error from mybatis code while executing a query that gets executed successfully many times during the day, but failed several times.
Below is the stacktrace:
org.apache.ibatis.ognl.NoSuchPropertyException: OrderXEO.cinemaAddress
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:280) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:80) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:73) ~[mybatis-3.3.0.jar:3.3.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
... 36 more
Caused by: org.apache.ibatis.ognl.NoSuchPropertyException: OrderXEO.cinemaAddress
at org.apache.ibatis.ognl.ObjectPropertyAccessor.getProperty(ObjectPropertyAccessor.java:151) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.OgnlRuntime.getProperty(OgnlRuntime.java:2434) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTProperty.getValueBody(ASTProperty.java:114) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:141) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTNotEq.getValueBody(ASTNotEq.java:50) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:61) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:494) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:458) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:44) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.TrimSqlNode.apply(TrimSqlNode.java:55) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:33) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:41) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:280) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:80) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:120) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:113) ~[mybatis-3.3.0.jar:3.3.0]
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:73) ~[mybatis-3.3.0.jar:3.3.0]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_45]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_45]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_45]
at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_45]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:358) ~[mybatis-spring-1.2.2.jar:1.2.2]
Any help to find root cause of above error will be greatly appreciated. Ps. We have met a similar problem(https://github.com/mybatis/mybatis-3/issues/199) when using mybatis-3.1.0, which has fixed in mybatis-3.3.0. Is this the same cause?
MyBatis version
3.3.1
Database vendor and version
Test case or example project
Steps to reproduce
Expected result
Actual result
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 37 (17 by maintainers)
@salten ,
Thank you for the follow-up!
MyBatis 3.3.1 (and 3.4.0) includes OGNL 3.1.2. I didn’t realize it, but in OGNL 3.1.2, getReadMethod() always returns null (because wrong parameter is specified in getMethodValue()) as you pointed out. So, you are right that this exception occurs in MyBatis 3.3.1 or 3.4.0 under heavy load even on Java 8.
In your case, upgrading MyBatis to 3.4.2 may fix the problem because this problem does not exist in the included OGNL [1] even though the race condition in getGetMethod() still exists. If you have to use 3.3.1, the interceptor solution might be a good workaround.
[1] Note that there still is another getReadMethod() issue with synthetic methods which causes the same exception on Java 6 and 7.
p.s. He didn’t mention, but it would make sense if @arebya specified an older version of OGNL .jar when he ran the demo app on Java 8u112.
@harawata I don’t know what version you used. In my mybatis3.3.1 version, the source which I decompile is :
The getReadMethod is :m = getReadMethod((target == null) ? null : target.getClass(), propertyName, 0); There is not the method which you write:
And the method “getReadMethod” is always return null…
Maybe your source version is different to mine…
@infear-on-the-way @rwtq2ksw , Are your getter methods override methods of super class/interface with different return types?
This could happen if the getter method generates a synthetic method, in theory.
That exception is thrown if this line is executed. It happens when both OgnlRuntime#getGetMethod() and OgnlRuntime#getReadMethod() return null.
OgnlRuntime#getGetMethod() could return null when multiple threads reach this line simultaneously. After the first thread put an entry to the cache at this line, the other threads return null from this line.
And OgnlRuntime#getReadMethod() could return null when the getter generates a synthetic (a.k.a. bridge) method [1]. Due to this JDK bug, java.beans.BeanInfo#getMethodDescriptors() could return synthetic version of the method and isMethodCallable() returns false in that case.
[1] It basically means that the method has a different return type than its super class or interface. In the following examples, the getId() methods generate synthetic methods.
@harawata Thank you for the answer. I have to use 3.3.1, and I added an interceptor to fix this ploblem…
I add a interceptor of mybatis to fix this problem. when the NoSuchPropertyException occurs, I retry once.
Yes, all properties have public getter methods. I tried debug the code, but i can’t reproduce the bug during debugging. Only fail when multiple requests run at the same time before server start. The same requests, launch sequentially, or before the first request response, run correctly.