Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested jars are not opened with runtime version set, causing classes in META-INF/versions to be ignored #38050

Closed
Hartigan opened this issue Oct 25, 2023 · 7 comments
Assignees
Labels
type: regression A regression from a previous release
Milestone

Comments

@Hartigan
Copy link

Hello

I tried new version of spring-framework 3.2.0-RC1 with spring.threads.virtual.enabled=true feature. But I faced issue with jar provided by bootJar: java.lang.UnsupportedOperationException: Virtual threads not supported on JDK <21
I prepared minimal reproducible example:

Environment:
openjdk 21 2023-09-19
OpenJDK Runtime Environment (build 21+35)
OpenJDK 64-Bit Server VM (build 21+35, mixed mode, sharing)

Project generated by https://start.spring.io/ with options:
Project: Gradle - Groovy
Language: Java
Spring Boot: 3.2.0-RC1
Packaging: Jar
Java: 21

DemoApplication.java contents:

package com.example.demo;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.task.VirtualThreadTaskExecutor;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		new VirtualThreadTaskExecutor().getVirtualThreadFactory();
		System.out.println("Hello world");
	}

}

Output for ./gradlew bootRun:

Welcome to Gradle 8.3!

Here are the highlights of this release:
 - Faster Java compilation
 - Reduced memory usage
 - Support for running on Java 20

For more details see https://docs.gradle.org/8.3/release-notes.html


> Task :bootRun
Hello world

BUILD SUCCESSFUL in 1s
4 actionable tasks: 3 executed, 1 up-to-date

Output for ./gradlew bootJar && java -jar ./build/libs/demo-0.0.1-SNAPSHOT.jar:

BUILD SUCCESSFUL in 1s
4 actionable tasks: 1 executed, 3 up-to-date
Exception in thread "main" java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:118)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:91)
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:53)
        at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:54)
Caused by: java.lang.UnsupportedOperationException: Virtual threads not supported on JDK <21
        at org.springframework.core.task.VirtualThreadDelegate.<init>(VirtualThreadDelegate.java:32)
        at org.springframework.core.task.VirtualThreadTaskExecutor.<init>(VirtualThreadTaskExecutor.java:41)
        at com.example.demo.DemoApplication.main(DemoApplication.java:10)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        ... 4 more
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 25, 2023
@jhoeller
Copy link

Spring's actual Virtual Threads support lives in a multi-release jar (https://openjdk.org/jeps/238), with alternative versions of those classes included for JDK 21+. This works fine for us in common setups. Is this somehow not being picked up in your scenario?

@Hartigan
Copy link
Author

But I build project with jdk 21 and run project on jdk 21. Should I create multi-release jar only java 21 environment?

@bclozel bclozel transferred this issue from spring-projects/spring-framework Oct 25, 2023
@philwebb
Copy link
Member

This looks like a regression with our new nested jar loader. For now you can add the following to your build to roll-back to the older implementation:

bootJar {
  loaderImplementation = org.springframework.boot.loader.tools.LoaderImplementation.CLASSIC
}

@Hartigan
Copy link
Author

Yes, this solution works. Is my task a duplicate? Should I close it?

@philwebb
Copy link
Member

@Hartigan No thanks, we need to fix it in Boot. We'll transfer the issue or create a new one and close this one ourselves.

@philwebb philwebb changed the title Different behavior between bootRun and bootJar for 3.2.0-RC1 Nested jars are not opened with runtime version set Oct 26, 2023
@philwebb
Copy link
Member

I bit of digging shows the assumption that the URLClassLoader will append #runtime to URLs so that they are opened with the correct runtime version set isn't true.

The code in jdk.internal.loader.URLClassPath does have some logic to do that, but only for JarLoader. We end up with the vanilla Loader due to this check.

I think we need to update our archive URLs to include #runtime.

@philwebb philwebb self-assigned this Oct 26, 2023
@philwebb
Copy link
Member

Unfortunately appending #runtime to the URL is not enough because it is lost here

@philwebb philwebb added type: regression A regression from a previous release and removed status: waiting-for-triage An issue we've not yet triaged labels Oct 26, 2023
@philwebb philwebb added this to the 3.2.0-RC2 milestone Oct 26, 2023
@wilkinsona wilkinsona changed the title Nested jars are not opened with runtime version set Nested jars are not opened with runtime version set, causing classes in META-INF/versions to be ignored Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: regression A regression from a previous release
Projects
None yet
Development

No branches or pull requests

4 participants