When starting my Quarkus project locally with mvn quarkus:dev
I have no errors when executing a function which utilizes JJWT.
However when I export my project into a docker container it gives me an error stating that it can’t find DefaultJwtBuilder.
When dockerizing my project I first execute
./mvnw package -Pnative -Dquarkus.native.container-build=true
as stated in the Quarkus docs for creating a Linux executable without GraalVM.
Followed by
docker build -f src/main/docker/Dockerfile.native -t quarkus-quickstart/getting-started .
When starting the project with Docker Desktop I get the error.
The dependencies I have in my pom.xml are the following.
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-api</artifactId> <version>0.11.2</version> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-impl</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt-jackson</artifactId> <version>0.11.2</version> <scope>runtime</scope> </dependency>
The detailed error message is
io.jsonwebtoken.lang.UnknownClassException: Unable to load class named [io.jsonwebtoken.impl.DefaultJwtBuilder] from the thread context, current, or system/application ClassLoaders. All heuristics have been exhausted. Class could not be found. Have you remembered to include the jjwt-impl.jar in your runtime classpath? at io.jsonwebtoken.lang.Classes.forName(Classes.java:92) at io.jsonwebtoken.lang.Classes.newInstance(Classes.java:136) at io.jsonwebtoken.Jwts.builder(Jwts.java:141) at org.roguedevelopment.logic.JWT.GenerateJWT(JWT.java:21) at org.roguedevelopment.logic.JWT_ClientProxy.GenerateJWT(JWT_ClientProxy.zig:224) at org.roguedevelopment.logic.AuthHandler.LoginUser(AuthHandler.java:62) at org.roguedevelopment.logic.AuthHandler_ClientProxy.LoginUser(AuthHandler_ClientProxy.zig:164) at org.roguedevelopment.controllers.AuthController.login(AuthController.java:72) at java.lang.reflect.Method.invoke(Method.java:566) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130) at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:643) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:507) at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:457) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:459) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:419) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:393) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:68) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261) at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161) at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247) at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:131) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:37) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:94) at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35) at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578) at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452) at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29) at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29) at java.lang.Thread.run(Thread.java:834) at org.jboss.threads.JBossThread.run(JBossThread.java:479) at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:517) at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
The dockerfile I use to build my docker image is
## Stage 1 : build with maven builder image with native capabilities FROM quay.io/quarkus/centos-quarkus-maven:20.2.0-java11 AS build COPY pom.xml /usr/src/app/ RUN mvn -f /usr/src/app/pom.xml -B de.qaware.maven:go-offline-maven-plugin:1.2.5:resolve-dependencies COPY src /usr/src/app/src USER root RUN chown -R quarkus /usr/src/app USER quarkus RUN mvn -f /usr/src/app/pom.xml -Pnative clean package ## Stage 2 : create the docker final image FROM registry.access.redhat.com/ubi8/ubi-minimal WORKDIR /work/ COPY --from=build /usr/src/app/target/*-runner /work/application # set up permissions for user `1001` RUN chmod 775 /work /work/application && chown -R 1001 /work && chmod -R "g+rwX" /work && chown -R 1001:root /work EXPOSE 8000 USER 1001 CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Any help would be greatly appreciated.
Advertisement
Answer
It doesn’t work because your are using native mode and the io.jsonwebtoken
library seems that does not support it.
Quarkus does its best to integrate libraries and make them work with native mode, by adding the pieces required by native mode. For native mode limitations, please check this link: https://www.graalvm.org/reference-manual/native-image/Limitations/.
Please check Quarkus JWT support that works with native mode: https://quarkus.io/guides/security-jwt.
If you really want to keep using io.jsonwebtoken
you may need to provide additional metadata to the native image build: https://quarkus.io/guides/writing-native-applications-tips.