Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MyBatis throws exceptions in native build #265

Open
Tikani opened this issue Feb 27, 2023 · 9 comments
Open

MyBatis throws exceptions in native build #265

Tikani opened this issue Feb 27, 2023 · 9 comments

Comments

@Tikani
Copy link

Tikani commented Feb 27, 2023

Hi!
We have a Quarkus project with versions:
Quarkus: 2.10.1.Final
quarkus-mybatis: 1.0.4
After building the project into native with GraalVM and launching the executable, the following exceptions are in a log:

Error querying database.  Cause: org.apache.ibatis.executor.ExecutorException: Error creating lazy proxy.  Cause: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
The error occurred while handling results
SQL: SELECT * FROM foo WHERE bar_id = ?
Cause: org.apache.ibatis.executor.ExecutorException: Error creating lazy proxy.  Cause: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:153)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
	at java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.ibatis.session.SqlSessionManager$SqlSessionInterceptor.invoke(SqlSessionManager.java:357)
	at jdk.proxy4.$Proxy352.selectList(Unknown Source)
	at org.apache.ibatis.session.SqlSessionManager.selectList(SqlSessionManager.java:206)
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80)
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
	at jdk.proxy4.$Proxy340.getAll(Unknown Source)
	at com.foo.bar.ClassA.updateStatistics(ClassA.java:134)
	at com.foo.bar.ClassA_VertxInvoker_updateStatistics_d89477c248378a626dcb124bf003d4ccfa6f3ffc.invokeBean(Unknown Source)
	at io.quarkus.vertx.runtime.EventConsumerInvoker.invoke(EventConsumerInvoker.java:41)
	at io.quarkus.vertx.runtime.VertxRecorder$3$1.handle(VertxRecorder.java:130)
	at io.quarkus.vertx.runtime.VertxRecorder$3$1.handle(VertxRecorder.java:100)
	at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:50)
	at io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:168)
	at io.vertx.core.eventbus.impl.MessageConsumerImpl.dispatch(MessageConsumerImpl.java:177)
	at io.vertx.core.eventbus.impl.HandlerRegistration$InboundDeliveryContext.next(HandlerRegistration.java:169)
	at io.vertx.core.eventbus.impl.HandlerRegistration$InboundDeliveryContext.dispatch(HandlerRegistration.java:134)
	at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:111)
	at io.vertx.core.eventbus.impl.HandlerRegistration.dispatch(HandlerRegistration.java:105)
	at io.vertx.core.eventbus.impl.MessageConsumerImpl.deliver(MessageConsumerImpl.java:183)
	at io.vertx.core.eventbus.impl.MessageConsumerImpl.doReceive(MessageConsumerImpl.java:168)
	at io.vertx.core.eventbus.impl.HandlerRegistration.lambda$receive$0(HandlerRegistration.java:56)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:833)
	at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
	at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
Caused by: org.apache.ibatis.executor.ExecutorException: Error creating lazy proxy.  Cause: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.crateProxy(JavassistProxyFactory.java:89)
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl.createProxy(JavassistProxyFactory.java:118)
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.createProxy(JavassistProxyFactory.java:59)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:648)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:404)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at org.apache.ibatis.executor.loader.ResultLoader.selectList(ResultLoader.java:81)
	at org.apache.ibatis.executor.loader.ResultLoader.loadResult(ResultLoader.java:70)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getNestedQueryMappingValue(DefaultResultSetHandler.java:874)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getPropertyMappingValue(DefaultResultSetHandler.java:511)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyPropertyMappings(DefaultResultSetHandler.java:487)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:411)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:89)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
	... 35 more
Caused by: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
	at com.oracle.svm.core.util.VMError.unimplemented(VMError.java:98)
	at java.lang.invoke.MethodHandles$Lookup.defineClass(MethodHandles.java:46)
	at org.apache.ibatis.javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:295)
	at org.apache.ibatis.javassist.util.proxy.DefineClassHelper$Java11.defineClass(DefineClassHelper.java:48)
	at org.apache.ibatis.javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:260)
	at org.apache.ibatis.javassist.util.proxy.FactoryHelper.toClass(FactoryHelper.java:154)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:640)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:624)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass1(ProxyFactory.java:560)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:481)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.create(ProxyFactory.java:828)
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.crateProxy(JavassistProxyFactory.java:87)
	... 67 more

MyDao mapper:

	@Select("SELECT * FROM my_table")
    @Results(value = {
          @Result(id = true, property = "uuid", column = "uuid", javaType = UUID.class, typeHandler = UuidTypeHandler.class),
          @Result(property = "foo", column = "uuid", javaType = List.class,
                many = @Many(select = "com.test.FooDAO.getByMyId", fetchType = FetchType.EAGER)),
          @Result(property = "bar", column = "uuid", javaType = Bar.class,
                many = @Many(select = "com.test.BarDAO.getByMyId", fetchType = FetchType.EAGER))
})
List<My> getAll();

ClassA.updateStatistics() event handler:

@ConsumeEvent(EventConstant.UPDATE)
public void updateStatistics(UpdateEvent event) {
    myDAO.getAll().forEach(my -> {
            ...
    });
}

Is there any workaround for this?

@zhfeng
Copy link
Collaborator

zhfeng commented Feb 28, 2023

Hi @Tikani

Is it possible to test with the lastest release 1.0.6?

@VojtenkoRN
Copy link

Hi there!
I'm on the same team as @Tikani
Versions was updated to:
Quarkus: 2.16.3.Final
quarkus-mybatis: 1.0.6
The exception is still there.

### The error may exist in com/test/MyDao.java (best guess)
### The error may involve com.test.MyDao.getByBarId
### The error occurred while handling results
### SQL: SELECT * FROM foo WHERE bar_id = ?
### Cause: org.apache.ibatis.executor.ExecutorException: Error creating lazy proxy.  Cause: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:153)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
	at java.lang.reflect.Method.invoke(Method.java:568)
	at org.apache.ibatis.session.SqlSessionManager$SqlSessionInterceptor.invoke(SqlSessionManager.java:357)
	at jdk.proxy4.$Proxy352.selectList(Unknown Source)
	at org.apache.ibatis.session.SqlSessionManager.selectList(SqlSessionManager.java:206)
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80)
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86)
	at jdk.proxy4.$Proxy340.getAll(Unknown Source)
	at com.foo.bar.ClassA.updateStatistics(QueueEventProcessor.java:134)
	at com.foo.bar.ClassA_VertxInvoker_updateStatistics_d89477c248378a626dcb124bf003d4ccfa6f3ffc.invokeBean(Unknown Source)
	at io.quarkus.vertx.runtime.EventConsumerInvoker.invoke(EventConsumerInvoker.java:41)
	at io.quarkus.vertx.runtime.VertxRecorder$3$1.handle(VertxRecorder.java:130)
	at io.quarkus.vertx.runtime.VertxRecorder$3$1.handle(VertxRecorder.java:100)
	at io.vertx.core.impl.EventLoopContext.emit(EventLoopContext.java:50)
	at io.vertx.core.impl.DuplicatedContext.emit(DuplicatedContext.java:168)
	at io.vertx.core.eventbus.impl.MessageConsumerImpl.dispatch(MessageConsumerImpl.java:177)
	at io.vertx.core.eventbus.impl.HandlerRegistration$InboundDeliveryContext.next(HandlerRegistration.java:169)
	at io.vertx.core.eventbus.impl.HandlerRegistration$InboundDeliveryContext.dispatch(HandlerRegistration.java:134)
	at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:111)
	at io.vertx.core.eventbus.impl.HandlerRegistration.dispatch(HandlerRegistration.java:105)
	at io.vertx.core.eventbus.impl.MessageConsumerImpl.deliver(MessageConsumerImpl.java:183)
	at io.vertx.core.eventbus.impl.MessageConsumerImpl.doReceive(MessageConsumerImpl.java:168)
	at io.vertx.core.eventbus.impl.HandlerRegistration.lambda$receive$0(HandlerRegistration.java:56)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:469)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:503)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:986)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:833)
	at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
	at com.oracle.svm.core.posix.thread.PosixPlatformThreads.pthreadStartRoutine(PosixPlatformThreads.java:202)
Caused by: org.apache.ibatis.executor.ExecutorException: Error creating lazy proxy.  Cause: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.crateProxy(JavassistProxyFactory.java:89)
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory$EnhancedResultObjectProxyImpl.createProxy(JavassistProxyFactory.java:118)
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.createProxy(JavassistProxyFactory.java:59)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(DefaultResultSetHandler.java:648)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:404)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at org.apache.ibatis.executor.loader.ResultLoader.selectList(ResultLoader.java:81)
	at org.apache.ibatis.executor.loader.ResultLoader.loadResult(ResultLoader.java:70)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getNestedQueryMappingValue(DefaultResultSetHandler.java:874)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getPropertyMappingValue(DefaultResultSetHandler.java:511)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyPropertyMappings(DefaultResultSetHandler.java:487)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getRowValue(DefaultResultSetHandler.java:411)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValuesForSimpleResultMap(DefaultResultSetHandler.java:361)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleRowValues(DefaultResultSetHandler.java:335)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSet(DefaultResultSetHandler.java:308)
	at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:201)
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65)
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:89)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151)
	... 35 more
Caused by: java.lang.UnsupportedOperationException: Defining new classes at runtime is not supported
	at com.oracle.svm.core.util.VMError.unimplemented(VMError.java:98)
	at java.lang.invoke.MethodHandles$Lookup.defineClass(MethodHandles.java:46)
	at org.apache.ibatis.javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:295)
	at org.apache.ibatis.javassist.util.proxy.DefineClassHelper$Java11.defineClass(DefineClassHelper.java:48)
	at org.apache.ibatis.javassist.util.proxy.DefineClassHelper.toClass(DefineClassHelper.java:260)
	at org.apache.ibatis.javassist.util.proxy.FactoryHelper.toClass(FactoryHelper.java:154)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass3(ProxyFactory.java:640)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass2(ProxyFactory.java:624)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass1(ProxyFactory.java:560)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.createClass(ProxyFactory.java:481)
	at org.apache.ibatis.javassist.util.proxy.ProxyFactory.create(ProxyFactory.java:828)
	at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.crateProxy(JavassistProxyFactory.java:87)
	... 67 more```

@zhfeng
Copy link
Collaborator

zhfeng commented Feb 28, 2023

OK, I see. And can you provide a simple reproducer project or test case ? It could be very helpful.

@VojtenkoRN
Copy link

https://github.com/VojtenkoRN/test
Run docker-compose up
Exception in app container.
Reproducer was maked on Linux machine, be aware of line endings trying it on Windows

@zhfeng
Copy link
Collaborator

zhfeng commented Mar 1, 2023

Thanks and I will take a look.

@Tikani
Copy link
Author

Tikani commented Mar 1, 2023

@zhfeng hope, a quick workaround exists (without rewriting of MyBatis low-level layers to bypass GraalVM limitations)

@zhfeng
Copy link
Collaborator

zhfeng commented Mar 2, 2023

I checked the reproducer and it looks like mybatis wants to create a new class for Result during runtime. But unfortunately it does not work in GraalVM native mode. Because in native execution where it is a closed world, it needs to know everything at build time. I have to say there is no quick workaound currently. I will try to find a way to create these classes at build time. TBH, I'm not very sure if it is possible or we have to do some tricks at Mybatis.

@Tikani
Copy link
Author

Tikani commented Mar 4, 2023

@zhfeng okay, i understood :( i've checked out similar projects (MyBatis + GraalVM), found this - https://github.com/mybatis/spring-native
maybe, you could pick some "hacks" from it

@zhfeng
Copy link
Collaborator

zhfeng commented Mar 8, 2023

Hmm, it's interesting! I just curious that did you folks try to test with spring-native and mybatis?
I just go through the codes but have not found any trick related to ProxyFactory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants