Quarkus原生模式集成JasperReport加载JRXML遇格式化错误求助
在Quarkus 2.6.0原生服务(GraalVM 21.3)中集成JasperReport,已通过配置文件指定相关类,编译和原生运行均正常,但执行以下代码加载jrxml文件时,出现日志格式化错误,无明确业务异常堆栈:
JasperCompileManager.compileReport(this.getClass().getClassLoader().getResourceAsStream("jasper/template.jrxml"));
初始错误日志
...
2023-05-10 13:26:55,789 DEBUG [net.sf.jas.eng.xml.BaseSaxParserFactory] (executor-thread-0) Instantiated SAX parser factory of type com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
2023-05-10 13:26:55,789 DEBUG [net.sf.jas.ext.DefaultExtensionsRegistry] (executor-thread-0) Loading registries for cache key jdk.internal.loader.ClassLoaders$AppClassLoader@483bf400
LogManager error of type FORMAT_FAILURE: Formatting error
Handler.reportError caught:
补充堆栈信息
Message is Formatting error Package Name org.jboss.logmanager.handlers ClassName org.jboss.logmanager.handlers.ConsoleHandler java.lang.Thread.getStackTrace(Thread.java:528) java.util.logging.Handler.reportError(Handler.java:18) org.jboss.logmanager.ExtHandler.reportError(ExtHandler.java:332) org.jboss.logmanager.handlers.WriterHandler.doPublish(WriterHandler.java:45) org.jboss.logmanager.ExtHandler.publish(ExtHandler.java:66) org.jboss.logmanager.ExtHandler.publishToNestedHandlers(ExtHandler.java:97) io.quarkus.bootstrap.logging.QuarkusDelayedHandler.doPublish(QuarkusDelayedHandler.java:80) org.jboss.logmanager.ExtHandler.publish(ExtHandler.java:66) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:334) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) org.jboss.logmanager.LoggerNode.publish(LoggerNode.java:341) org.jboss.logmanager.Logger.logRaw(Logger.java:750) org.jboss.logmanager.Logger.log(Logger.java:708) org.jboss.logging.JBossLogManagerLogger.doLogf(JBossLogManagerLogger.java:53) org.jboss.logging.Logger.errorf(Logger.java:1743) io.quarkus.vertx.http.runtime.QuarkusErrorHandler.handle(QuarkusErrorHandler.java:127) io.quarkus.vertx.http.runtime.QuarkusErrorHandler.handle(QuarkusErrorHandler.java:30) io.vertx.ext.web.impl.RouteState.handleFailure(RouteState.java:1199) io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:160) io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:201) io.vertx.ext.web.impl.RouterImpl.handleFailure(RouterImpl.java:253) io.vertx.ext.web.impl.RouteState.handleFailure(RouteState.java:1199) io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:160) io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141) io.vertx.ext.web.impl.RoutingContextImpl.doFail(RoutingContextImpl.java:604) io.vertx.ext.web.impl.RoutingContextImpl.fail(RoutingContextImpl.java:192) io.vertx.ext.web.impl.RoutingContextImpl.fail(RoutingContextImpl.java:181) io.vertx.ext.web.impl.RoutingContextWrapper.fail(RoutingContextWrapper.java:100) io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:158) io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:91) io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543) org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449) org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478) org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) java.lang.Thread.run(Thread.java:829) com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:600) com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192) Code is 5
重写WriterHandler后的日志
RESTEASY002315: PathInfo: %s
023-05-10 13:26:55,789 DEBUG [net.sf.jas.eng.xml.BaseSaxParserFactory] (executor-thread-0) Instantiated SAX parser factory of type com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl
2023-05-10 13:26:55,789 DEBUG [net.sf.jas.ext.DefaultExtensionsRegistry] (executor-thread-0) Loading registries for cache key
jdk.internal.loader.ClassLoaders$AppClassLoader@483bf400
RoutingContext failure (500)
HTTP Request to %s failed, error id: %s
io.quarkus.vertx.http.runtime.QuarkusErrorHandler
LogManager error of type FORMAT_FAILURE: Formatting error
Handler.reportError caught:
1. 修复日志模板缺失问题
日志中%s占位符未被替换,说明Quarkus错误处理的日志模板在原生模式下未正确加载。需将日志资源包纳入原生镜像:
- 在
application.properties添加配置:quarkus.native.additional-build-args=-H:IncludeResources=org/jboss/logging/**/*.properties - 或在
native-image.properties中指定:Args=-H:IncludeResources=org/jboss/logging/**/*.properties
2. 补充JasperReport原生模式配置
JasperReport在原生环境下需要额外的反射、资源配置:
- 添加反射配置:在
application.properties中指定quarkus.native.reflection-config-files=reflection-config.json,并创建reflection-config.json文件:[ { "name": "net.sf.jasperreports.engine.xml.BaseSaxParserFactory", "allDeclaredConstructors": true, "allPublicConstructors": true, "allDeclaredMethods": true, "allPublicMethods": true }, { "name": "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl", "allDeclaredConstructors": true, "allPublicConstructors": true } ] - 确保jrxml资源被打包:
quarkus.native.additional-build-args=-H:IncludeResources=jasper/**/*
3. 预编译Jasper模板
避免原生模式下编译jrxml,提前将模板编译为.jasper文件:
- 构建阶段用Maven/Gradle插件预编译jrxml,将
.jasper文件放入资源目录 - 运行时直接加载编译后的模板:
JasperFillManager.fillReport(this.getClass().getClassLoader().getResourceAsStream("jasper/template.jasper"), parameters, dataSource);
4. 升级Quarkus版本
Quarkus 2.6.0版本较旧,原生模式的日志、第三方库兼容性问题较多,建议升级到2.x系列稳定版本(如2.16.x),可修复大量原生模式下的已知问题。
内容的提问来源于stack exchange,提问作者Luisao

