Vaadin Gradle Skeleton Starter compatibility with Java 17

Hello! I would like to run Vaadin Flow on stable Debian. It has Tomcat 10 and Java 17. Vaadin Gradle Skeleton Starter works fine when I run ./gradlew appRun, but if I change the application server in build.gradle from jetty11 to tomcat10, I get the error:

SEVERE: Allocate exception for servlet [com.vaadin.flow.server.startup.ServletDeployer]
java.lang.ExceptionInInitializerError: Exception java.lang.NoSuchFieldError: JAVA_21 [in thread "main"]
        at com.vaadin.copilot.Copilot.<clinit>(Copilot.java:28)
        at com.vaadin.copilot.CopilotIndexHtmlLoader.serviceInit(CopilotIndexHtmlLoader.java:44)
        at com.vaadin.flow.server.VaadinService.lambda$init$0(VaadinService.java:271)
...

Why does the problem occur on Tomcat 10 but not Jetty 11 and is there any way to disable Copilot?

You can exclude Copilot if you want, and that particular error should go away. However, the real problem causing the NoSuchFieldError is that somehow switching from Jetty to Tomcat introduces an older version of javaparser into the project. Not super clear why but I also see the issue

Ok, so if you run

./gradlew appRun --debug

you can see that it adds

    "servletContainerClasspath": [
...
        "/.../.gradle/wrapper/dists/gradle-8.7-bin/bhs2wmbdwecv87pi65oeuq5iu/gradle-8.7/lib/javaparser-core-3.17.0.jar",

which is what causes the problem. Still not sure why that would be added to the tomcat container classpath but then it overrides the version in the application itself

Thanks @Artur! Should I create an issue to Vaadin Gradle Skeleton Starter project?

How to do that? I tried

gretty {
    contextPath = "/"
    servletContainer = "tomcat10"
    jvmArgs = [
            "-Dvaadin.copilot.enabled=false"
    ]
}

but it doesn’t work.

I created an issue for Gretty, let’s see what they say Gretty adds javaparser to Tomcat classpath, overriding the web app javaparser version · Issue #317 · gretty-gradle-plugin/gretty · GitHub

You need to exclude the dependency, not just disable it. Something like

    // Vaadin
    implementation("com.vaadin:vaadin-core") {
        exclude group: 'com.vaadin', module: 'hilla-dev'
        exclude group: "com.vaadin", module: "copilot"
    }

It looks like Gretty sets the delegate=true flag to the WebAppLoader (gretty/libs/gretty-runner-tomcat/src/main/groovy/org/akhikhl/gretty/TomcatServerConfigurer.groovy at 52f9077b87625accd929dd38db37bc9aa8380d3f · gretty-gradle-plugin/gretty · GitHub) causing the common and system class loaders to have higher priority.

Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

  • Bootstrap classes of your JVM
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/.jar* of your web application
  • System class loader classes (described above)
  • Common class loader classes (described above)

If the web application class loader is configured with <Loader delegate="true"/> then the order becomes:

  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • Common class loader classes (described above)
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/.jar* of your web application

https://tomcat.apache.org/tomcat-9.0-doc/class-loader-howto.html