Skip to content

Using custom servlet in Quarkus app fails with ClassNotFoundException #19

@mvysny

Description

@mvysny

Description of the bug / feature

Using custom servlet in a Quarkus+Vaadin app causes DevModeInitializer to fail with ClassNotFoundException.

The reason is that Quarkus uses multiple classloaders; it loads Vaadin jars in one classloader and the app code (including the Servlet class) in another classloader. The "Vaadin classloader" is then unable to load the Servlet class.

The exception stacktrace follows:

2021-01-07 09:52:04,044 ERROR [io.qua.run.boo.StartupActionImpl] (Quarkus Main Thread) Error running Quarkus: java.lang.reflect.InvocationTargetException
	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 io.quarkus.runner.bootstrap.StartupActionImpl$3.run(StartupActionImpl.java:134)
	at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.ExceptionInInitializerError
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at java.base/java.lang.Class.newInstance(Class.java:584)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:61)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:38)
	at io.quarkus.runtime.Quarkus.run(Quarkus.java:104)
	at io.quarkus.runner.GeneratedMain.main(GeneratedMain.zig:29)
	... 6 more
Caused by: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:178)
	... 15 more
Caused by: java.lang.RuntimeException: java.lang.RuntimeException: javax.servlet.ServletException: java.lang.reflect.InvocationTargetException
	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder.bootServletContainer(UndertowDeploymentRecorder.java:519)
	at io.quarkus.deployment.steps.UndertowBuildStep$build-649634386.deploy_0(UndertowBuildStep$build-649634386.zig:1948)
	at io.quarkus.deployment.steps.UndertowBuildStep$build-649634386.deploy(UndertowBuildStep$build-649634386.zig:40)
	at io.quarkus.runner.ApplicationImpl.<clinit>(ApplicationImpl.zig:158)
	... 15 more
Caused by: java.lang.RuntimeException: javax.servlet.ServletException: java.lang.reflect.InvocationTargetException
	at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:255)
	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder.bootServletContainer(UndertowDeploymentRecorder.java:508)
	... 18 more
Caused by: javax.servlet.ServletException: java.lang.reflect.InvocationTargetException
	at com.vaadin.flow.server.startup.ClassLoaderAwareServletContainerInitializer.onStartup(ClassLoaderAwareServletContainerInitializer.java:99)
	at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:205)
	at io.undertow.servlet.core.DeploymentManagerImpl$1.call(DeploymentManagerImpl.java:187)
	at io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:42)
	at io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
	at io.quarkus.undertow.runtime.UndertowDeploymentRecorder$10$1.call(UndertowDeploymentRecorder.java:554)
	at io.undertow.servlet.core.DeploymentManagerImpl.deploy(DeploymentManagerImpl.java:253)
	... 19 more
Caused by: java.lang.reflect.InvocationTargetException
	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 com.vaadin.flow.server.startup.ClassLoaderAwareServletContainerInitializer.onStartup(ClassLoaderAwareServletContainerInitializer.java:94)
	... 25 more
Caused by: javax.servlet.ServletException: Servlet class name (org.acme.servlet.MyServlet) can't be found!
	at com.vaadin.flow.server.startup.DevModeInitializer.process(DevModeInitializer.java:198)
	... 30 more
Caused by: java.lang.ClassNotFoundException: org.acme.servlet.MyServlet
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
	at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
	at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:412)
	at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:365)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:315)
	at com.vaadin.flow.server.startup.DevModeInitializer.isVaadinServletSubClass(DevModeInitializer.java:218)
	at com.vaadin.flow.server.startup.DevModeInitializer.process(DevModeInitializer.java:191)
	... 30 more

Minimal reproducible example

Please see the attached app.

vaadin-quarkus.zip

  1. Unzip the app
  2. Run mvn -C clean package quarkus:dev

Expected behavior

Vaadin should use Thread's context class loader to load the classes

Actual behavior

Vaadin uses Class.forName() which uses DevModeInitializer.class.getClassLoader().

Versions:

- Vaadin / Flow version: 14.4.4/2.4.3
- Java version: 11
- Application Server (if applicable): Quarkus+Vertx+Undertow

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions