在micronaut框架中使用JavaCPP转换为GraalVM原生镜像的Java程序问题

问题描述

环境:

  • 操作系统:Ubuntu 20.04 64 位 LTS。
  • JDK:11.0.10
  • JavaCPP:1.5.6
  • OpenCV:4.5.3
  • Micronaut:2.5.9

最近我有一个关于计算机视觉的项目。在这个项目中,它使用 Micronaut 作为主要框架。并且它还使用了用 JavaCPP 构建的 OpenCV。

我自己使用以下命令从 JavaCPP 构建了 OpenCV:

mvn install --projects openblas,opencv  -Djavacpp.platform=linux-x86_64

我从 JavaCPP 的 FAQ 中读到它说 JavaCPP 支持 GraalVM NativeImage。

我的代码和build.gradle如下:

build.gradle:

plugins {
    id("groovy")
    id("com.github.johnrengelman.shadow") version "7.0.0"
    id("io.micronaut.application") version "1.5.3"
}

version = "0.1"
group = "com.example"

repositories {
    mavenLocal()
    mavenCentral()
}

micronaut {
    testRuntime("spock2")
    processing {
        incremental(true)
        annotations("com.example.*")
    }
}

dependencies {
    annotationProcessor("org.projectlombok:lombok")
    annotationProcessor("info.picocli:picocli-codegen")
    implementation("info.picocli:picocli")
    implementation("io.micronaut:micronaut-runtime")
    implementation("io.micronaut.picocli:micronaut-picocli")
    implementation("javax.annotation:javax.annotation-api")
    compileOnly("org.projectlombok:lombok")
    runtimeOnly("ch.qos.logback:logback-classic")
    compileOnly("org.graalvm.nativeimage:svm")

    implementation("io.micronaut:micronaut-validation")

    testImplementation("io.micronaut:micronaut-http-client")

    implementation('org.bytedeco:opencv:4.5.3-1.5.6-SNAPSHOT')

}


application {
    mainClass.set("com.example.NativeJavacppTestCommand")
}
java {
    sourceCompatibility = JavaVersion.toVersion("11")
    targetCompatibility = JavaVersion.toVersion("11")
}

代码

package com.example;

import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.context.ApplicationContext;

import lombok.extern.slf4j.Slf4j;
import org.bytedeco.opencv.opencv_core.Mat;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;

@Command(name = "native-javacpp-test",description = "...",mixinStandardHelpOptions = true)
@Slf4j
public class NativeJavacppTestCommand implements Runnable {

    @Option(names = {"-v","--verbose"},description = "...")
    boolean verbose;

    public static void main(String[] args) throws Exception {
        PicocliRunner.run(NativeJavacppTestCommand.class,args);
    }

    public void run() {
        // business logic here
        if (verbose) {
            System.out.println("Hi!");
        }
        Mat mat = new Mat();
        log.info("Hello,World");
    }
}

构建步骤:

sh gradlew shadowJar
sh gradlew nativeImage

当我使用以下命令运行 jar 文件时,它运行良好。

java -Djava.library.path=/opt/javacpp-presets/opencv/target/native/org/bytedeco/opencv/linux-x86_64:/opt/javacpp-presets/openblas/target/native/org/bytedeco/openblas/linux-x86_64 -jar build/libs/native-javacpp-test-0.1-all.jar

当我运行构建的本机映像时。发生以下错误

./build/native-image/application

10:40:05.322 [main] INFO  i.m.context.env.DefaultEnvironment - Established active environments: [cli]
Warning: Could not create an instance of class org.bytedeco.javacpp.presets.javacpp: java.lang.InstantiationException: Type `org.bytedeco.javacpp.presets.javacpp` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
Warning: Could not create an instance of class org.bytedeco.javacpp.presets.javacpp: java.lang.InstantiationException: Type `org.bytedeco.javacpp.presets.javacpp` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
Warning: Could not create an instance of class org.bytedeco.javacpp.presets.javacpp: java.lang.InstantiationException: Type `org.bytedeco.javacpp.presets.javacpp` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
Warning: Version of org.bytedeco:openblas Could not be found.
Warning: Could not create an instance of class org.bytedeco.openblas.presets.openblas_nolapack: java.lang.InstantiationException: Type `org.bytedeco.openblas.presets.openblas_nolapack` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
Warning: Could not create an instance of class org.bytedeco.openblas.presets.openblas: java.lang.InstantiationException: Type `org.bytedeco.openblas.presets.openblas` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
Warning: Version of org.bytedeco:opencv Could not be found.
Warning: Could not create an instance of class org.bytedeco.opencv.presets.opencv_core: java.lang.InstantiationException: Type `org.bytedeco.opencv.presets.opencv_core` can not be instantiated reflectively as it does not have a no-parameter constructor or the no-parameter constructor has not been added explicitly to the native image.
Exception in thread "main" java.lang.NoClassDefFoundError: java.lang.classNotFoundException: org.bytedeco.javacpp.presets.javacpp
    at org.bytedeco.javacpp.Loader.load(Loader.java:1217)
    at org.bytedeco.javacpp.Loader.load(Loader.java:1157)
    at org.bytedeco.javacpp.Loader.load(Loader.java:1133)
    at org.bytedeco.opencv.opencv_core.AbstractArray.<clinit>(AbstractArray.java:18)
    at com.oracle.svm.core.classinitialization.ClassInitializationInfo.invokeClassInitializer(ClassInitializationInfo.java:375)
    at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:295)
    at java.lang.class.ensureInitialized(DynamicHub.java:553)
    at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:260)
    at java.lang.class.ensureInitialized(DynamicHub.java:553)
    at com.oracle.svm.core.classinitialization.ClassInitializationInfo.initialize(ClassInitializationInfo.java:260)
    at com.example.NativeJavacppTestCommand.run(NativeJavacppTestCommand.java:30)
    at picocli.CommandLine.executeUserObject(CommandLine.java:1939)
    at picocli.CommandLine.access$1300(CommandLine.java:145)
    at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2352)
    at picocli.CommandLine$RunLast.handle(CommandLine.java:2346)
    at picocli.CommandLine$RunLast.handle(CommandLine.java:2311)
    at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
    at picocli.CommandLine.execute(CommandLine.java:2078)
    at io.micronaut.configuration.picocli.PicocliRunner.run(PicocliRunner.java:137)
    at io.micronaut.configuration.picocli.PicocliRunner.run(PicocliRunner.java:114)
    at com.example.NativeJavacppTestCommand.main(NativeJavacppTestCommand.java:22)
Caused by: java.lang.classNotFoundException: org.bytedeco.javacpp.presets.javacpp
    at com.oracle.svm.core.hub.ClassForNameSupport.forName(ClassForNameSupport.java:64)
    at java.lang.class.forName(DynamicHub.java:1308)
    at org.bytedeco.javacpp.Loader.load(Loader.java:1212)
    ... 20 more

如何让我的代码与原生图像一起运行?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)