本机编译 java.lang.NoSuchMethodException:apache-poi 的 org.apache.logging.log4j.message.DefaultFlowMessageFactory.<init>() 异常

问题描述 投票:0回答:1

我有一个带有

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.*
java gradle apache-poi log4j graalvm
1个回答
0
投票

这是一个已知问题(参见Issue #1539),原因是 Log4j 2.x 实例化消息工厂的方式,而 GraalVM 显然不支持这种方式。

© www.soinside.com 2019 - 2024. All rights reserved.