NullPointerException при инициализации VaadinServlet с использованием Vaadin 14

Я работаю над обновлением приложения Vaadin 8 до Vaadin 14. Мне пришлось вручную определить расширение VaadinServlet, а не использовать автоматическую регистрацию сервлета Vaadin 14, поскольку мне нужно, чтобы оно было сопоставлено с определенным шаблоном URL. Я использую web.xml для настройки сервлета так же, как он был успешно настроен для Vaadin 8.

Когда мой сервлет инициализируется, я получаю ServletException, вызванный NullPointerException кодом Ваадина. Я посмотрел на исходный код и увидел, что исключение возникает, когда Vaadin пытается получить экземпляр Lookup из ServletContext сервлета и вместо этого возвращает 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

person Evan    schedule 13.05.2021    source источник


Ответы (1)


LookupServletContainerInitializer - это javax.servlet.ServletContainerInitializer, который должен автоматически запускаться контейнером сервлетов во время инициализации.

Есть две типичные ситуации, в которых эта часть инициализации пропускается:

  • web.xml настроен на пропуск определенных шагов, например потому что для metadata-complete установлено значение "истина" или имеется пустой <absolute-ordering>.
  • Если вы встраиваете контейнер сервлетов вместо того, чтобы запускать его как автономный сервер, возможно, потребуется явно включить эту функциональность. В случае Jetty вам необходимо включить модуль AnnotationConfiguration и, возможно, также установить свойство ContainerIncludeJarPattern, чтобы включить как минимум файл .jar, который включает VaadinServlet и связанные классы.

Третья альтернатива состоит в том, что вы имитируете ServletContainerInitializer, вручную создавая и вызывая инициализаторы, используемые Vaadin. Требуется немного проб и ошибок, чтобы точно определить, какие инициализаторы нужно запускать с какими параметрами. Я создал пример того, как это может выглядеть, в https://github.com/Legioth/vaadin-without-classpath-scanning, но это было до появления LookupServletContainerInitializer, поэтому вам придется позаботиться об этом отдельно.

person Leif Åstrand    schedule 14.05.2021
comment
Спасибо за вашу помощь. Я последовал приведенному вами примеру и больше не получаю NullPointerException, хотя теперь получаю ошибку 404 для одного из ресурсов в /VAADIN/static/client, и я не уверен, связана ли она. Не могли бы вы уточнить, какие классы Ваадина я должен перейти к DevModeInitializer? Я вижу, вы передали ему класс каждого компонента, который вы использовали в MainView. Обязательно ли передавать ему класс каждого типа компонента, который я использую в своем приложении? - person Evan; 17.05.2021
comment
Если вы делаете что-то вручную, вам нужно просмотреть аннотацию @HandlesTypes DevModeInitializer и передать классы для всего, что имеет отношение к пути к классам приложения, который реализует или аннотируется любым из перечисленных интерфейсов или аннотаций. Затем повторите то же самое для всех остальных ServletContainerInitializer подклассов, которые являются частью Vaadin. Или, в качестве альтернативы, сконфигурируйте контейнер сервлетов так, чтобы он делал это автоматически за вас. /VAADIN/static/client может иметь отношение к @PWA. - person Leif Åstrand; 18.05.2021