0

Environment:

  • OS: Ubuntu 20.04 64bit LTS.
  • JDK: 11.0.10
  • JavaCPP: 1.5.6
  • OpenCV: 4.5.3
  • Micronaut: 2.5.9

Recently I have a project regarding computer vision. In this project, it uses Micronaut as the main framework. And it also uses OpenCV built with JavaCPP.

I built OpenCV from JavaCPP by myself with below command:

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

I have read from JavaCPP's FAQ on which it said that JavaCPP supports GraalVM NativeImage.

My code and build.gradle are as below:

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")
}

code:

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");
    }
}

Build steps:

sh gradlew shadowJar
sh gradlew nativeImage

When I ran the jar file with below command, it worked fine.

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

When I ran the built native image. Below error happened:

./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

How to let my code run with native image?

geocodezip
  • 158,664
  • 13
  • 220
  • 245
wureka
  • 731
  • 1
  • 11
  • 26
  • There's an issue that's been fixed recently regarding that. Please give it a try with JavaCPP 1.5.6-SNAPSHOT: http://bytedeco.org/builds/ – Samuel Audet Jul 24 '21 at 03:29
  • 1
    @SamuelAudet Thanks. it works now. I took https://github.com/bytedeco/gradle-javacpp/tree/master/samples/javacv-demo as the reference, and modified build.gradle and settings.gradle of my micronaut project. – wureka Jul 24 '21 at 04:18

0 Answers0