使用 Vaadin 14 初始化 VaadinServlet 时出现 NullPointerException

NullPointerException when initializing VaadinServlet using Vaadin 14

我正在努力将 Vaadin 8 应用程序升级到 Vaadin 14。我不得不手动定义 VaadinServlet 的扩展,而不是使用 Vaadin 14 的自动 servlet 注册,因为我需要将它映射到特定的URL 模式。我正在使用 web.xml 配置 servlet,其配置方式与为 Vaadin 8 成功配置的方式相同。

当我的 servlet 初始化时,我得到一个 ServletException,这是由来自 Vaadin 代码的 NullPointerException 引起的。我查看了源代码,我可以看到当 Vaadin 试图从 servlet 的 ServletContext 获取 Lookup 实例而不是 returns null 时发生异常。我发现 Lookup 实例应该添加到 LookupServletContainerInitializer 中的上下文中,但在我的情况下似乎没有发生这种情况。

有谁知道可能导致此问题的原因是什么? NullPointerException 的堆栈跟踪如下。

Caused by: java.lang.NullPointerException
    at com.vaadin.flow.server.DeploymentConfigurationFactory.getTokenFileFromClassloader(DeploymentConfigurationFactory.java:341)
    at com.vaadin.flow.server.DeploymentConfigurationFactory.getTokenFileContents(DeploymentConfigurationFactory.java:311)
    at com.vaadin.flow.server.DeploymentConfigurationFactory.readBuildInfo(DeploymentConfigurationFactory.java:181)
    at com.vaadin.flow.server.DeploymentConfigurationFactory.createInitParameters(DeploymentConfigurationFactory.java:174)
    at com.vaadin.flow.server.VaadinServlet.createDeploymentConfiguration(VaadinServlet.java:152)
    at com.vaadin.flow.server.VaadinServlet.createServletService(VaadinServlet.java:190)
    at com.vaadin.flow.server.VaadinServlet.init(VaadinServlet.java:77)
    at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:602)
    ... 28 more

LookupServletContainerInitializer 是一个 javax.servlet.ServletContainerInitializer,它应该在初始化期间由 servlet 容器自动 运行。

这部分初始化被跳过的典型情况有两种:

  • web.xml 配置为跳过某些步骤,例如因为 metadata-complete 设置为 true 或者 <absolute-ordering>.
  • 为空
  • 如果您要嵌入 servlet 容器而不是 运行将其作为独立服务器,则可能需要明确启用该功能。对于 Jetty,您需要启用 AnnotationConfiguration 模块,并且可能还设置 ContainerIncludeJarPattern 属性 以至少包含包含 VaadinServlet 和相关 类.

第三种选择是通过手动实例化和调用 Vaadin 使用的初始化程序来模拟 ServletContainerInitializer。需要一些反复试验才能准确地发现哪些初始化程序需要 运行 以及哪些参数。我在 https://github.com/Legioth/vaadin-without-classpath-scanning 中创建了一个示例,但那是在引入 LookupServletContainerInitializer 之前,因此您必须单独处理它。