Loading static VAADIN resources when classpath is too long on windows

On windows if your classpath is too long you have to use a command line shortening (like a jar manifest for example).
If you do that you cant load the static VAADIN resources anymore:

GET https://localhost:8080/VAADIN/static/push/vaadinPush.js?v=1.0.0.beta3 404 ()
GET https://localhost:8080/VAADIN/static/client/client-38BF774AF840394A49AA4FEE6427A49C.cache.js 404 ()

Do you know of a solution for that?

Hi Marc, Could you provide us some more information for reproducing this problem? maybe some code example?

Hi,

We are using:

def vaadinVersion = "10.0.0.beta3"
def vaadinFlowVersion = "1.0.0.beta3"

Together with Spring Boot 2.0 and Gradle 4.4.
Our Gradle file looks like the following:

buildscript {
    repositories {
        mavenCentral()
        maven { url "https://repo.spring.io/release" }
        maven { url "https://repo.spring.io/milestone" }
        maven { url "https://repo.spring.io/snapshot" }
    }

    dependencies {
        classpath "org.springframework:springloaded:1.2.6.RELEASE"
    }
}

plugins {
    id "com.dorongold.task-tree" version "1.3"
    id "io.spring.dependency-management" version "1.0.4.RELEASE"
    id "org.springframework.boot" version "2.0.0.RELEASE"
    id "org.sonarqube" version "2.5"
}

apply plugin: "java"
apply plugin: 'jacoco'
apply plugin: "idea"
apply plugin: "application"
apply plugin: "war"
apply plugin: "idea"

import org.apache.tools.ant.taskdefs.condition.Os

jar {
    from("src/main/webapp") {
        include "frontend/**/*"
    }
}

idea {
    module {
        inheritOutputDirs = false
        outputDir = file("$buildDir/classes/main/")
    }
}

group = "com.company.frontend"
description = "Frontend"
version "${version}"

mainClassName = "com.company.frontend.Application"

def vaadinVersion = "10.0.0.beta3"
def vaadinFlowVersion = "1.0.0.beta3"
def frontendWorkingDir = "src/main/webapp/frontend"

sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenLocal()
    mavenCentral()
    maven { url "http://repo.spring.io/release" }
    maven { url "http://repo.spring.io/snapshot" }
    maven { url "http://repo.spring.io/milestone" }
    maven { url "https://maven.vaadin.com/vaadin-prereleases" }
    maven { url "https://dl.bintray.com/webjars/maven" }
    maven { url "https://repo.vaadin.com/nexus/content/repositories/flow" }
    maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }
}

configurations {
    compile.exclude module: "spring-boot-starter-tomcat"
    compile.exclude module: "vaadin-charts-flow"
    compile.exclude module: "vaadin-board-flow"
    compile.exclude group: "org.webjars.bower"
    compile.exclude group: "org.webjars.bowergithub.vaadin"
    compile.exclude group: "org.webjars.bowergithub.polymer"
    compile.exclude group: "org.webjars.bowergithub.polymerelements"
    compile.exclude group: "org.webjars.bowergithub.webcomponent"
}

dependencyManagement {
    imports {
        mavenBom "com.vaadin:vaadin-bom:${vaadinVersion}"
    }
    dependencies {
        dependency(group: 'org.projectlombok', name: 'lombok', version: '1.16.18')
    }
}

dependencies {
    compile("org.springframework.boot:spring-boot-starter-webflux")
    compile("org.springframework.boot:spring-boot-starter-undertow")
    compile("org.springframework.boot:spring-boot-starter-test")

    /* Components */
	...

    /* Metrics */
    ...

    /* Vaadin stuff */
    compile("com.vaadin:flow-spring-boot-starter:${vaadinFlowVersion}")
    compile("com.vaadin:vaadin-core:${vaadinVersion}")

    /* Security stuff */
    ...
}

/* Some Tasks here */

/* Some Testing and Code Coverage here */

/* Some Sonar here */

We have many dependencies so the max length of 32k command line characters is reached. If it is reached you are getting the error:

CreateProcess error=206, The filename or extension is too long.

To avoid this you need command line shortening. But when you do this (for example by enabling it in intellij idea or by using gradle plugins or tasks to create a jar manifest) you do not get the error anymore and you can start the spring boot application using gradles bootRun but you cannot load the static VAADIN resources:

GET https://localhost:8080/VAADIN/static/push/vaadinPush.js?v=1.0.0.beta3 404 ()
GET https://localhost:8080/VAADIN/static/client/client-38BF774AF840394A49AA4FEE6427A49C.cache.js 404 ()

Currently Im not sure if this is related to the classpath length. It appeared first after I needed to enable command line shortening but I just removed some dependencies and now my classpath isnt too long anymore so I disabled command line shortening. But I still get all the 404 messages for all /* resources.

Is there a general problem with Vaadin and Spring Boot?

I remember we have fixed some issues related to /* resources in the recent flow. So i will suggest you to start with update the vaadin version to the newest 10.0.0.beta10 (which matches flow version 1.0.0.beta10)

Whats the compatible flow-spring-boot-starter version for vaadin flow 1.0.0.beta10?

Oh, in this case, update the artifactID of flow-spring-boot-starter to vaadin-spring-boot-starter.

Warning:<i><b>root project 'frontend-application': Web Facets/Artifacts will not be configured properly</b>
Details: org.gradle.api.internal.artifacts.ivyservice.DefaultLenientConfiguration$ArtifactResolveException: Could not resolve all files for configuration ':runtimeClasspath'.
Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve com.vaadin:vaadin-spring-boot-starter:1.0.0.beta10.
Required by:
    project :
Caused by: org.gradle.internal.resolve.ModuleVersionResolveException: Could not resolve com.vaadin:vaadin-spring-boot-starter:1.0.0.beta10.
Caused by: org.gradle.api.resources.ResourceException: Could not get resource 'http://oss.jfrog.org/artifactory/oss-snapshot-local/com/vaadin/vaadin-spring-boot-starter/1.0.0.beta10/vaadin-spring-boot-starter-1.0.0.beta10.pom'.
Caused by: org.gradle.internal.resource.transport.http.HttpErrorStatusCodeException: Could not GET 'http://oss.jfrog.org/artifactory/oss-snapshot-local/com/vaadin/vaadin-spring-boot-starter/1.0.0.beta10/vaadin-spring-boot-starter-1.0.0.beta10.pom'. Received status code 409 from server: </i>

Seems like it is not available. The last version there is flow-spring-boot-starter 10.0.0.beta3. vaadin-spring-boot-starter isnt available at all. On vaadin-prereleases the vaadin-spring-boot-starter exists but also only in 10.0.0.beta3: https://maven.vaadin.com/vaadin-prereleases/com/vaadin/vaadin-spring-boot-starter/

If you are using vaadin-platform in your dependency, you don’t need to specify a version for the vaadin-spring-boot-stater as it will come from the vaadin-bom.

flow-spring-boot-starter is the old artifactId, but it has been deprecated now. The new one is vaadin-spring-boot-stater and the version is 10.0.0.beta3, the newest.

Ok I will try that out. It will take some time until I give feedback since I have to refactor all my components since the HasClickListeners does not exists anymore.

Sure, i hope this will help you and comment more if there is still problem with this. Also you can create a ticket in the [flow repository]
(https://github.com/vaadin/flow/issues)

Hi Marc, have you found a solution for the static VAADIN resources?

I think we have the same problem as you have. We also use gradle instead of maven. We start our application with IntelliJ’s Spring Boot Run Configuration that has command line shortening. Instead of Undertow we use embeded Tomcat.

I have debugged Vaadin’s Bakery App (that uses maven and embedded Jetty) with our application and compared how webjar resources are handled. Tomcat has the following code (I think it’s almost the same for Jetty):

// StandardRoot.java
private final List<List<WebResourceSet>> allResources = new ArrayList<>();
{
	allResources.add(preResources);
	allResources.add(mainResources); // is size 1
	allResources.add(classResources);
	allResources.add(jarResources); // is size 50+ for maven and zero for gradle
	allResources.add(postResources);
}

With maven the jarResources contains all the webjars that I expect to be there. With gradle it’s empty. If I change our application to use embedded Jetty, jarResources is still empty. And you have the same problem with Undertow.

So I think the problem is something with gradle. Maybe something that we don’t configure correctly?

Hi!

Yes, we found a solution by accident :slight_smile:
Last week we switched from beta3 to rc1 and it automatically solved the problem.

Ok. That didn’t worked for us. :frowning:
Are you running the application with IntelliJ and Spring Boot Run Configuration?

Yes. Correct. IntelliJ idea and Spring Boot Run Configuration.

Just for information.

I found a temporary solution that works for us. It is described in the Spring Boot issue https://github.com/spring-projects/spring-boot/issues/9513

I have copied the file AbstractServletWebServerFactory.java into my project and added the code that reads the manifest file to add URL for each jar. Now when I start with IntelliJ Spring Boot Run Configuration or with ./gradlew bootRun it works as as expected.

Spring Boot 2.0.3.RELEASE, Gradle 4.6, Vaadin Flow 10.0.0.rc5.

This is a bit of an old topic now but I’m encountering the same issues with Vaadin 14. All my projects use the manifest style classpath (Linux server) and as everyone has reported in this thread, the system is unable to load any resource.

Anyone figured out a permanent solution? My application is started via a shell script and not via Maven/Gradle plugins.

Gradle 5.2, Spring Boot 2.1.7.Release, com.vaadin:vaadin-spring-boot-starter:14.0.0, Vaadin running on Jetty

We are still using the “solution” as I described above. We have tried to remove it without success. We have not yet upgraded to Vaadin 14. Our setup now is: Gradle 5.2, Spring Boot 2.1.0.RELEASE and Vaadin 13.0.8

Thanks Oskar. I haven’t been able to find anything better than your solution so far in 2019. For reference, my edit of AbstractServletWebServerFactory is:

    /**
     * Workarounds heavily inspired from:
     * https://vaadin.com/forum/thread/17079950/loading-static-vaadin-resources-when-classpath-is-too-long-on-windows
     * https://github.com/spring-projects/spring-boot/issues/9513
     */
    protected final List<URL> getUrlsOfJarsWithMetaInfResources() {
        try {
            ClassPathResource classPathResource = new ClassPathResource("META-INF/MANIFEST.MF");

            Set<URL> urlSet = new LinkedHashSet<>();
            if (classPathResource.exists()) {
                URL url = classPathResource.getURL();
                Manifest manifest = new Manifest(url.openStream());

                String classPath = manifest.getMainAttributes().getValue("Class-Path");

                if (classPath != null) {
                    for (String urlStr : classPath.split(" ")) {
                        try {
                            urlSet.add(new URL(urlStr));
                        } catch (MalformedURLException ex) {
                            throw new AssertionError();
                        }
                    }
                }

            }
            urlSet.addAll(this.staticResourceJars.getUrls());
            return new ArrayList<>(urlSet);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }

Thank Oskar and cycle222. Your solutions helped us as well.

Adding spring-boot-dev-tools alone (as suggested in https://github.com/spring-projects/spring-boot/issues/9513) did not solve the problems for our developers working under windows, we also had to patch AbstractServletWebServerFactory.

For reference: Spring-Boot 2.1.8, Gradle 5.0, Vaadin 14, IntelliJ with “manifest” classpath-fix for Windows machines.