I am creating a Quarkus 3 application to create a QR code given an url. In non-native build it works fine, but when packaging it in native mode, it gives me an error about some missing path.
Caused by: java.lang.UnsatisfiedLinkError: no awt in java.library.path at org.graalvm.nativeimage.builder/com.oracle.svm.core.jdk.NativeLibrarySupport.loadLibraryRelative(NativeLibrarySupport.java:136) at java.base@17.0.8/java.lang.ClassLoader.loadLibrary(ClassLoader.java:50)
Here's the pom.xml:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-awt</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.5.2</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.5.2</version>
</dependency>
Here is the code i am using to generate the QR Code:
public class QRCodeGenerator {
public static byte[] getQRCodeBytes(String text, int width, int height)
throws WriterException, IOException {
String imageFormat = "png"; // could be "gif", "tiff", "jpeg"
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.
encode(text, BarcodeFormat.QR_CODE, width, height);
ByteArrayOutputStream pngOutputStream =
new ByteArrayOutputStream();
MatrixToImageWriter.writeToStream(bitMatrix, imageFormat, pngOutputStream);
return pngOutputStream.toByteArray();
}
public static String getQRCodeBase64(String text, int width, int height)
throws WriterException, IOException {
return encodeBase64String(getQRCodeBytes(text, width, height));
}
private static String encodeBase64String(byte[] binaryData) {
return Base64.getEncoder().encodeToString(binaryData);
}
}
I am asking if anyone has a solution for the error, or another way to handle the QR code generation. Many thanks!
EDIT: Here is the dockerfile (i am using Quarkus default native Dockerfile, with a minor modification):
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
WORKDIR /work/
COPY ./build_files/*-runner /work/application
EXPOSE 8080
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
Also here is my Jenkins pipeline config to build this project:
mkdir -p /var/xplorer/xplorer-label-dev/build_files
cp target/xplorer-label-*.jar /var/xplorer/xplorer-label-dev/build_files/xplorer-label.jar
cp target/xplorer-label-*-runner /var/xplorer/xplorer-label-dev/build_files/xplorer-label-runner
cp -f Dockerfile /var/xplorer/xplorer-label-dev/Dockerfile
cp -f docker-compose.yml /var/xplorer/xplorer-label-dev/docker-compose.yml
When we execute the native build, we see that some *.so
-Files are also listed as artifacts:
$ ./mvnw --define native clean verify
...
Produced artifacts:
/project/libawt.so (jdk_library)
/project/libawt_headless.so (jdk_library)
/project/libawt_xawt.so (jdk_library)
/project/libfontmanager.so (jdk_library)
/project/libjava.so (jdk_library_shim)
/project/libjavajpeg.so (jdk_library)
/project/libjvm.so (jdk_library_shim)
/project/liblcms.so (jdk_library)
/project/libmlib_image.so (jdk_library)
...
These libraries need to be copied to the container as well:
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
WORKDIR /work/
COPY ./build_files/*.so /work/
COPY ./build_files/*-runner /work/application
EXPOSE 8080
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
I have a very similar application on github.com
. This is my corresponding containerfile
(github.com
):
ARG DISTROLESS_IMAGE="quay.io/quarkus/quarkus-distroless-image:2.0@sha256:142abd361c081de7e4f7922362eb73e3d98f4ca060178688aeb4c969101e853b"
FROM ${DISTROLESS_IMAGE} as runner
ARG APP_DIR=/deployment
ARG UID=1001
USER root
WORKDIR ${APP_DIR}
COPY \
--chmod=444 \
target/*.so /lib/
COPY \
--chmod=111 \
target/*-runner ${APP_DIR}/application
ENV LANGUAGE='en_US:en'
USER ${UID}:${UID}
ENTRYPOINT [ "./application" ]