Hello MyBatis,
I try to upgrade our application to Java 17. Sadly I hit a few bumps on the way. With Java 17 you can't anymore allow reflection for anyone with --illegel-access=permit
.
From my understanding the proper way to fix this, is that mybatis supports the Java module system and correctly specify what it needs. So it is not an unnamed module anymore.
Current package it tries to access are java.lang and java.util (accessing List). For the 2nd one I can provide the stacktrace soon as well, if you need it.
Can you please help me out? Thank you very much.
MyBatis version
3.5.7
Database vendor and version
MySQL 8.0.17
Test case or example project
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private final long java.lang.Long.value accessible: module java.base does not "opens java.lang" to unnamed module @7334aada
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
at org.apache.ibatis.reflection.invoker.GetFieldInvoker.invoke(GetFieldInvoker.java:38)
at org.apache.ibatis.reflection.wrapper.BeanWrapper.getBeanProperty(BeanWrapper.java:164)
at org.apache.ibatis.reflection.wrapper.BeanWrapper.get(BeanWrapper.java:49)
at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:122)
at org.apache.ibatis.executor.keygen.SelectKeyGenerator.processGeneratedKeys(SelectKeyGenerator.java:76)
Workaround
Workaround is to add following statement to the java process that opens.
--add-opens
java.base/java.lang=ALL-UNNAMED
--add-opens
java.base/java.util=ALL-UNNAMED
Comment From: harawata
Hello @keiki85 ,
It seems that you incorrectly specify keyProperty
.
If you need further assistance, please create a small demo project like these and share it on your GitHub repo.
Comment From: keiki85
Hey @harawata . Thanks for the fast reply.
I thought this is a more general issue with Java 17 that's why I didn't thought about creating an example project yet. Or digging more into my personal configuration. With Java 11 I don't have any issues though. I see what I can provide.
Comment From: keiki85
I found the cause for the first issue.
We have following code:
@Update("UPDATE SEQUENCE_TABLE SET ID = LAST_INSERT_ID(ID+1)")
@SelectKey(statement = "SELECT LAST_INSERT_ID() as value", keyProperty = "value", before = false, resultType = Long.class)
long createId( LongRef updatedId );
The problem is that "value" is on one hand the field/getter name in "LongRef", but also in the resulting java.lang.Long itself. That's why in org/apache/ibatis/executor/keygen/SelectKeyGenerator.java:75 the test succeeds for having a getter for java.lang.Long value field and tries to make it accessible.
After changing the field name to "number" in LongRef and the result of the query everthingy works fine as it doesn't find any getter.
Comment From: GeorgeSalu
@keiki85 are you running mybatis on java 17 with no problems?
Comment From: keiki85
@GeorgeSalu Not yet that's why I'm here. Most works fine though.
The next issue I'm facing is related to ognl. I could add "--add-open" to it, but is not a long term fix.
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make public boolean java.util.ImmutableCollections$List12.isEmpty() accessible: module java.base does not "opens java.util" to unnamed module @55740540
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199)
at java.base/java.lang.reflect.Method.setAccessible(Method.java:193)
at org.apache.ibatis.ognl.AccessibleObjectHandlerPreJDK9.setAccessible(AccessibleObjectHandlerPreJDK9.java:58)
at org.apache.ibatis.ognl.OgnlRuntime.invokeMethod(OgnlRuntime.java:1232)
at org.apache.ibatis.ognl.OgnlRuntime.callAppropriateMethod(OgnlRuntime.java:1979)
at org.apache.ibatis.ognl.ObjectMethodAccessor.callMethod(ObjectMethodAccessor.java:68)
at org.apache.ibatis.ognl.OgnlRuntime.callMethod(OgnlRuntime.java:2055)
at org.apache.ibatis.ognl.ASTMethod.getValueBody(ASTMethod.java:97)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
at org.apache.ibatis.ognl.ASTChain.getValueBody(ASTChain.java:141)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
at org.apache.ibatis.ognl.ASTAnd.getValueBody(ASTAnd.java:61)
at org.apache.ibatis.ognl.SimpleNode.evaluateGetValueBody(SimpleNode.java:212)
at org.apache.ibatis.ognl.SimpleNode.getValue(SimpleNode.java:258)
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:586)
at org.apache.ibatis.ognl.Ognl.getValue(Ognl.java:550)
at org.apache.ibatis.scripting.xmltags.OgnlCache.getValue(OgnlCache.java:46)
at org.apache.ibatis.scripting.xmltags.ExpressionEvaluator.evaluateBoolean(ExpressionEvaluator.java:32)
at org.apache.ibatis.scripting.xmltags.IfSqlNode.apply(IfSqlNode.java:34)
at org.apache.ibatis.scripting.xmltags.ChooseSqlNode.apply(ChooseSqlNode.java:35)
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.lambda$apply$0(MixedSqlNode.java:32)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.apache.ibatis.scripting.xmltags.MixedSqlNode.apply(MixedSqlNode.java:32)
at org.apache.ibatis.scripting.xmltags.DynamicSqlSource.getBoundSql(DynamicSqlSource.java:39)
at org.apache.ibatis.mapping.MappedStatement.getBoundSql(MappedStatement.java:305)
at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:87)
at jdk.internal.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64)
at jdk.proxy2/jdk.proxy2.$Proxy91.query(Unknown Source)
at jdk.internal.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:64)
at jdk.proxy2/jdk.proxy2.$Proxy91.query(Unknown Source)
at jdk.internal.reflect.GeneratedMethodAccessor45.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.apache.ibatis.plugin.Invocation.proceed(Invocation.java:49)
Comment From: keiki85
Looks like ognl is setting isEmpty (of java/util/ImmutableCollections.java:574) "accessible". Even though it's already callable, but not "accessible" as term of java reflection. I guess I create a ticket for them...
Comment From: harawata
@keiki85 ,
That error may occur if you write <if test="x.isEmpty()">
.
Try <if test="x.empty">
or <if test="x.isEmpty">
instead.
isEmpty
is one of the Pseudo-Properties for Collections.
Comment From: keiki85
@harawata Thank you very much! That solved my issue.
I'm using isEmpty without brackets now.
So far I have no further issues. Seems like the issue was only the false use of the library.
Comment From: onefawn
、
如果您编写 .尝试或改为。
<if test="x.isEmpty()">``<if test="x.empty">``<if test="x.isEmpty">
isEmpty
是 Collections 的伪属性之一。
通过这个解决了问题,thanks
Comment From: hazendaz
Replaced my comment. Please open new issues rather than comments on years old tickets. Also please write in English.