javaspringspring-bootjava-web-startjnlp

Exception when using Spring Boot and Java Web Start (JNLP)


I'm building an application with Spring Boot. I packaged it as an executable jar. I'd like to deploy this app using Java Web Start. I wrote a JNLP file, but when I'm trying to run it, I get he following Exception :

java.lang.IllegalStateException: Unable to determine code source archive from \\localhost\printpoc.jar
at org.springframework.boot.loader.Launcher.createArchive(Launcher.java:126)
at org.springframework.boot.loader.ExecutableArchiveLauncher.<init>(ExecutableArchiveLauncher.java:38)
at org.springframework.boot.loader.JarLauncher.<init>(JarLauncher.java:35)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.sun.javaws.Launcher.executeApplication(Unknown Source)
at com.sun.javaws.Launcher.executeMainClass(Unknown Source)
at com.sun.javaws.Launcher.doLaunchApp(Unknown Source)
at com.sun.javaws.Launcher.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Here is my JNLP file :

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://localhost/" href="printpoc.jnlp">
<information>
    <vendor>Me</vendor>
    <homepage href="http://localhost/" />
    <description>PrintPoc</description>
</information>
<security>
    <all-permissions/>
</security>
<resources>
    <j2se version="1.8+" />
    <jar href="printpoc.jar" />
</resources>
<application-desc main-class="org.springframework.boot.loader.JarLauncher" />

I wanted to try that, but the layout MODULE doesn't existe anymore. I tried with ZIP, NONE etc, still no success. Here is my pom.xml :

        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <layout>JAR</layout>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Coud you please help me ?


Solution

  • This looks to me like a Spring bug. From the source:

    ProtectionDomain protectionDomain = getClass().getProtectionDomain();
    CodeSource codeSource = protectionDomain.getCodeSource();
    URI location = (codeSource != null) ? codeSource.getLocation().toURI() : null;
    String path = (location != null) ? location.getSchemeSpecificPart() : null;
    
    if (path == null) {
        throw new IllegalStateException("Unable to determine code source archive");
    }
    
    File root = new File(path);
    if (!root.exists()) {
        throw new IllegalStateException(
                "Unable to determine code source archive from " + root);
    }
    

    The problem is this line:

    String path = (location != null) ? location.getSchemeSpecificPart() : null;
    

    From the URI documentation:

    At the highest level a URI reference (hereinafter simply "URI") in string form has the syntax

    [scheme:]scheme-specific-part[#fragment]

    So, in the URI http://localhost/printpoc.jnlp, the scheme-specific part is //localhost/printpoc.jnlp. Spring then tries to treat that as a file name, which of course does not exist, which is why you are seeing the exception you’re seeing.

    The Spring code is incorrect. It wrongly assumes you can make a file name out of any URI. Only file: URIs can be safely converted to file names, and that is correctly done with new File(location) or Paths.get(location).

    I’m not sure what the solution is. It appears the Spring Boot launcher is assuming the .jar is always a local file. I doubt it can work with a .jar file obtained via HTTP.