我有一个带有
picocli
和 apache-poi
: 的小型 Java 应用程序
构建.gradle
plugins {
id 'java'
id 'application'
id 'org.graalvm.buildtools.native' version '0.10.1'
}
group = 'com.example'
version = '1.0-SNAPSHOT'
repositories {
mavenCentral()
}
dependencies {
implementation 'info.picocli:picocli:4.7.5'
annotationProcessor 'info.picocli:picocli-codegen:4.7.5'
implementation('org.apache.poi:poi:5.2.5')
implementation('org.apache.poi:poi-ooxml:5.2.5')
}
compileJava {
options.compilerArgs += ["-Aproject=${project.group}/${project.name}"]
}
application {
mainClass = 'com.example.NativeCompileExample'
}
NativeCompileExample.java
package com.ppfeiler.clf;
import org.apache.poi.hssf.usermodel.HSSFPrintSetup;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import picocli.CommandLine;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.Callable;
@CommandLine.Command(
name = "example",
mixinStandardHelpOptions = true,
description = "example description")
public class NativeCompileExample implements Callable<Integer> {
@CommandLine.Parameters(description = "The input file")
private File inputFile;
@CommandLine.Parameters(description = "The output file")
private File outputFile;
public static void main(String[] args) throws IOException {
final int exitCode = new CommandLine(new NativeCompileExample()).execute(args);
System.exit(exitCode);
}
@Override
public Integer call() throws Exception {
try (final XSSFWorkbook workbook = new XSSFWorkbook(inputFile)) {
for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
final XSSFSheet sheet = workbook.getSheetAt(i);
sheet.getPrintSetup().setLandscape(true);
sheet.getPrintSetup().setPaperSize(HSSFPrintSetup.A4_PAPERSIZE);
}
workbook.write(new FileOutputStream(outputFile));
}
return 0;
}
}
我使用 graalvm-21 通过 gradle 使用本机编译来编译应用程序(通过 sdkman 安装。版本
21.0.2-graalce
):
./gradlew clean build nativeCompile
当我运行编译的应用程序时,我看到以下错误:
Exception in thread "main" java.lang.ExceptionInInitializerError
at org.apache.logging.log4j.LogManager.<clinit>(LogManager.java:61)
at org.apache.poi.ooxml.POIXMLDocumentPart.<clinit>(POIXMLDocumentPart.java:56)
at [email protected]/java.lang.Class.ensureInitialized(DynamicHub.java:601)
at [email protected]/java.lang.Class.ensureInitialized(DynamicHub.java:601)
at com.example.NativeCompileExample.call(NativeCompileExample.java:37)
at com.example.NativeCompileExample.call(NativeCompileExample.java:18)
at picocli.CommandLine.executeUserObject(CommandLine.java:2041)
at picocli.CommandLine.access$1500(CommandLine.java:148)
at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2461)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2453)
at picocli.CommandLine$RunLast.handle(CommandLine.java:2415)
at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2273)
at picocli.CommandLine$RunLast.execute(CommandLine.java:2417)
at picocli.CommandLine.execute(CommandLine.java:2170)
at com.example.NativeCompileExample.main(NativeCompileExample.java:31)
at [email protected]/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH)
Caused by: java.lang.IllegalStateException: java.lang.InstantiationException: org.apache.logging.log4j.message.DefaultFlowMessageFactory
at org.apache.logging.log4j.spi.AbstractLogger.createDefaultFlowMessageFactory(AbstractLogger.java:239)
at org.apache.logging.log4j.spi.AbstractLogger.<init>(AbstractLogger.java:138)
at org.apache.logging.log4j.status.StatusLogger.<init>(StatusLogger.java:141)
at org.apache.logging.log4j.status.StatusLogger.<clinit>(StatusLogger.java:91)
... 16 more
Caused by: java.lang.InstantiationException: org.apache.logging.log4j.message.DefaultFlowMessageFactory
at [email protected]/java.lang.Class.newInstance(DynamicHub.java:719)
at org.apache.logging.log4j.spi.AbstractLogger.createDefaultFlowMessageFactory(AbstractLogger.java:237)
... 19 more
Caused by: java.lang.NoSuchMethodException: org.apache.logging.log4j.message.DefaultFlowMessageFactory.<init>()
at [email protected]/java.lang.Class.checkMethod(DynamicHub.java:1075)
at [email protected]/java.lang.Class.getConstructor0(DynamicHub.java:1238)
at [email protected]/java.lang.Class.newInstance(DynamicHub.java:706)
... 20 more
在没有本地编译的情况下运行应用程序时,它可以工作。 我认为这与 graalvm 不支持 log4j 有关。
有什么技巧可以告诉 apache-poi 使用不同的东西或者只是为日志记录类提供一个空的实现吗?
我尝试通过 gradle 从
log4j-api
依赖项中排除 apache-poi
:
implementation('org.apache.poi:poi:5.2.5') {
exclude group: 'org.apache.logging.log4j', module: 'log4j-api'
}
implementation('org.apache.poi:poi-ooxml:5.2.5') {
exclude group: 'org.apache.logging.log4j', module: 'log4j-api'
}
但是,当然错误并没有消失,因为现在
apache-poi
抱怨类丢失了。
我也尝试添加
log4j-over-slf4j
但它提供了与 apache-poi
使用的不同的包:
log4j-over-slf4j
中的包结构是org.apache.log4j.*
apache-poi
使用以下包中的日志类:org.apache.logging.log4j.*
这是一个已知问题(参见Issue #1539),原因是 Log4j 2.x 实例化消息工厂的方式,而 GraalVM 显然不支持这种方式。