jetty-project / jetty-alpn

Implementation of ALPN (Application Layer Protocol Negotiation) Specification for OpenJDK 7 or greater
48 stars 27 forks source link

ALPN is not compatible with both Java 8 and 9 #15

Closed nhenneaux closed 6 years ago

nhenneaux commented 7 years ago

I have updated my dependencies to use the following Maven dependencies to work with Java 9.

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-alpn-java-server</artifactId>
            <version>${jetty.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-alpn-java-client</artifactId>
            <version>${jetty.version}</version>
        </dependency>

It works well with Java 9. However, it does not work with Java 8 since the classes has been compile with target 9 (see the following snippet from the pom.xml of jetty-alpn-java-server).

<build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.9</source>
                    <target>1.9</target>
                    <release>9</release>
                </configuration>
            </plugin>
        </plugins>
    </build>

I got the following error using Java 8.

java.lang.UnsupportedClassVersionError: org/eclipse/jetty/alpn/java/server/JDK9ServerALPNProcessor has been compiled by a more recent version of the Java Runtime (class file version 53.0), this version of the Java Runtime only recognizes class file versions up to 52.0

    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:361)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:348)
    at java.util.ServiceLoader$LazyIterator.nextService(ServiceLoader.java:370)
    at java.util.ServiceLoader$LazyIterator.next(ServiceLoader.java:404)
    at java.util.ServiceLoader$1.next(ServiceLoader.java:480)
    at org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory.<init>(ALPNServerConnectionFactory.java:49)

I use Java 8_144 and 9.0.1 with Jetty 9.4.7.

Could you build the jar with target 1.8 such that it also works with Java 8 projects?

sbordet commented 7 years ago

You need to include the dependency for jetty-alpn-java-[client|server] only when using JDK 9. This is easily done with a Maven profile.

The jar cannot be built with JDK 8 because it uses JDK 9 specific APIs.

nhenneaux commented 7 years ago

This means it is not possible to build a library that can be used for both versions :-( it's a big limitation.

On 9 Nov 2017 12:15 pm, "Simone Bordet" notifications@github.com wrote:

You need to include the dependency for jetty-alpn-java-[client|server] only when using JDK 9. This is easily done with a Maven profile.

The jar cannot be built with JDK 8 because it uses JDK 9 specific APIs.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/jetty-project/jetty-alpn/issues/15#issuecomment-343124066, or mute the thread https://github.com/notifications/unsubscribe-auth/AJOnRiKvr5QKeANkCmfuEYzzsboW6FCjks5s0t60gaJpZM4QXufH .

gregw commented 7 years ago

Typically we have used either the jetty start.jar modules or Maven profiles to assemble the correct jars.

Unfortunately we can't make this jar a Multi release jar because it users the service loader which cannot be version Ed. Perhaps we can put a dummy java 8 version in the jar that is a noop. I've reopened to consider this.

Also you can now use conscript for ssl which has the same alpn for Java 8 and java 9.

nhenneaux commented 7 years ago

Right Maven profile can be used but only if you directly use Jetty library not if you are building a library that uses Jetty.

What about using a condition just like the NegotiatingServerConnectionFactory class (see https://github.com/eclipse/jetty.project/blob/jetty-9.4.x-1200/jetty-server/src/main/java/org/eclipse/jetty/server/NegotiatingServerConnectionFactory.java#L41) to determine the JVM version and use the service loader only when it is Java 9?

nhenneaux commented 6 years ago

I managed to find a workaround but I don't think it is a recommended way.

Using Jetty 9.4.8, with the following dependencies (in this order I suppose) and build with Java 9. I just have to add alpn-boot (-Xbootclasspath/p:/path/to/alpn-boot.jar) for running with Java 8 and the modules for Java 9 (--add-modules java.activation,java.xml.bind).

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-alpn-java-server</artifactId>
            <version>${jetty.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-alpn-java-client</artifactId>
            <version>${jetty.version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-alpn-openjdk8-server</artifactId>
            <version>${jetty.version}</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-alpn-openjdk8-client</artifactId>
            <version>${jetty.version}</version>
        </dependency>
sbordet commented 6 years ago

Yes this is the correct way.

Artifacts jetty-alpn-java-[client|server] are built by Jetty with target JDK 9, while artifacts jetty-alpn-openjdk8-[client|server] are built with target JDK 8.

A library may ship all artifacts, and Jetty will use the ServiceLoader to load the right implementation at runtime, preferring jetty-alpn-openjdk8-* when the runtime is JDK 8 and jetty-alpn-java-* when the runtime is JDK 9.

Unfortunately you still need the bootclasspath for JDK 8 only, so it's not a completely transparent solution, as you have to change the command line depending on the JDK version.

gregw commented 6 years ago

Note that you may wish to consider using the conscrypt SSL provider with jetty. Not only is it much faster than native SSL, but it supports ALPN in both java8 and java9 without the need to modify the boot path.

https://www.eclipse.org/jetty/documentation/9.4.x/jetty-ssl-distribution.html

Documentation has also been updated for the next release: https://github.com/eclipse/jetty.project/commit/904acea9feb0d8d432a16462e696c8cb0f755124

lindenquan commented 5 years ago

no more warning, after I excluded JDK 9 version Alpn in Gradle

configurations.forEach {
  it.exclude("org.eclipse.jetty", "jetty-alpn-java-server")
  it.exclude("org.eclipse.jetty", "jetty-alpn-server")
}