javakotlinquarkusquarkus-qute

java.lang.UnsatisfiedLinkError when using Qute TypeSafe Templates with Kotlin


When trying to use Quarkus Qute Typesafe Templates with Kotlin (converting the static class into an object as per the code below), I run into an UnsatisfiedLinkError at runtime.

The code at issue:

@Path("/subscriber")
@Produces(MediaType.TEXT_HTML)
@Consumes(MediaType.TEXT_HTML)
class SubscriberResource {

    @CheckedTemplate
    object Templates {
        external fun new(): TemplateInstance
    }

    @GET
    fun get(): TemplateInstance {
        return Templates.new()
    }
}

with the template being available in resources/templates/SubscriberResource/new.html.

The project builds fine, but when I attempt to open the view, I get the exception given below.

I've also tried making the object a companion object, but it didn't help.

Any idea what's missing?

java.lang.UnsatisfiedLinkError: 'io.quarkus.qute.TemplateInstance com.app.subscriber.SubscriberResource$Templates.new()' at com.app.subscriber.SubscriberResource$Templates.new(Native Method) at com.app.subscriber.SubscriberResource.get(SubscriberResource.kt:23) at com.app.subscriber.SubscriberResource_Subclass.get$$superaccessor1(SubscriberResource_Subclass.zig:189) at com.app.subscriber.SubscriberResource_Subclass$$function$$6.apply(SubscriberResource_Subclass$$function$$6.zig:29) at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54) at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:63) at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:49) at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(InvocationInterceptor_Bean.zig:521) at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41) at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41) at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32) at com.app.subscriber.SubscriberResource_Subclass.get(SubscriberResource_Subclass.zig:147) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/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:138) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.access$000(VertxRequestHandler.java:41) at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler$1.run(VertxRequestHandler.java:93) at io.quarkus.runtime.CleanableExecutor$CleaningRunnable.run(CleanableExecutor.java:231) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2415) 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.base/java.lang.Thread.run(Thread.java:834) at org.jboss.threads.JBossThread.run(JBossThread.java:501) Resulted in: org.jboss.resteasy.spi.UnhandledException: java.lang.UnsatisfiedLinkError: 'io.quarkus.qute.TemplateInstance com.app.subscriber.SubscriberResource$Templates.new()' at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:106) at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:372) at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519) ... 18 more


Solution

  • Finally figured out a solution, adding @JvmStatic to the external object function solves it:

        @CheckedTemplate
        object Templates {
            @JvmStatic
            external fun new(): TemplateInstance
        }