mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-10-07 15:39:29 +00:00
Support multi-release sources in Eclipse
Prior to this commit, the Java 21 and Java 24 multi-release sources in spring-core could not be developed or tested within Eclipse, since an Eclipse project supports only a single Java compliance level. This commit configures Eclipse projects that use the multiReleaseJar plugin with the highest multi-release version as their Java baseline (Java 24 for spring-core) and includes the corresponding multi-release source folders. Types which are overridden by a multi-release source folder are excluded from lower source folders, and higher source folders are placed first so that the debugger's source lookup resolves overriding types. A lower baseline can be configured via the "eclipseJavaBaseline" project property: for example, -PeclipseJavaBaseline=17. See gh-37397
This commit is contained in:
+101
-5
@@ -68,13 +68,109 @@ eclipse.classpath.file.whenMerged {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove classpath entries for multi-release source sets (such as "src/main/java21")
|
||||
// and their Gradle output (such as "build/classes/java/java21"), since an Eclipse
|
||||
// project supports only a single Java compliance level. Consequently, features
|
||||
// managed via the multiReleaseJar plugin cannot be built or tested within Eclipse.
|
||||
// Since an Eclipse project supports only a single Java compliance level, projects
|
||||
// that use the multiReleaseJar plugin are configured with a single Java baseline
|
||||
// within Eclipse. By default, the highest multi-release version is used (such as
|
||||
// Java 24 for spring-core), so that the corresponding sources can be developed
|
||||
// and tested within Eclipse. A different baseline can be configured via the
|
||||
// "eclipseJavaBaseline" project property: for example, -PeclipseJavaBaseline=17.
|
||||
// Multi-release source folders for versions above the baseline are not configured
|
||||
// as source folders in Eclipse (the sources themselves remain untouched), and types
|
||||
// which are overridden by a multi-release source folder are excluded from lower
|
||||
// source folders in Eclipse.
|
||||
def javaBaseline = 17
|
||||
|
||||
def multiReleaseVersions = {
|
||||
sourceSets.names.findAll { it ==~ /java\d+/ }.collect { (it - 'java') as int }
|
||||
}
|
||||
|
||||
def eclipseJavaBaseline = {
|
||||
def releaseVersions = multiReleaseVersions()
|
||||
if (releaseVersions.isEmpty()) {
|
||||
return javaBaseline
|
||||
}
|
||||
return (project.hasProperty('eclipseJavaBaseline') ?
|
||||
(project.property('eclipseJavaBaseline') as int) : releaseVersions.max())
|
||||
}
|
||||
|
||||
// Return the Java version of the supplied source folder: 0 for "src/main/java",
|
||||
// 21 for "src/main/java21", or null if it is not a Java source folder.
|
||||
def javaVersionOf = { SourceFolder folder ->
|
||||
def matcher = (folder.path =~ /^src\/(main|test)\/java(\d*)$/)
|
||||
if (!matcher.matches()) {
|
||||
return null
|
||||
}
|
||||
return (matcher.group(2) ? (matcher.group(2) as int) : 0)
|
||||
}
|
||||
|
||||
// Return the paths of all Java source files in the supplied directory, relative to
|
||||
// that directory: for example, "org/springframework/core/task/VirtualThreadDelegate.java"
|
||||
// for "src/main/java21/org/springframework/core/task/VirtualThreadDelegate.java".
|
||||
def relativeJavaFiles = { String dir ->
|
||||
def root = file(dir).toPath()
|
||||
return fileTree(dir).matching { include '**/*.java' }.collect {
|
||||
root.relativize(it.toPath()).toString().replace('\\', '/')
|
||||
}
|
||||
}
|
||||
|
||||
// Remove existing source folders, since their exclusion patterns depend on the
|
||||
// configured baseline and would otherwise result in duplicate entries.
|
||||
eclipse.classpath.file.beforeMerged { classpath ->
|
||||
if (!multiReleaseVersions().isEmpty()) {
|
||||
classpath.entries.removeAll { it instanceof SourceFolder }
|
||||
}
|
||||
}
|
||||
|
||||
eclipse.jdt.file.whenMerged { jdt ->
|
||||
def baseline = JavaVersion.toVersion(eclipseJavaBaseline())
|
||||
jdt.sourceCompatibility = baseline
|
||||
jdt.targetCompatibility = baseline
|
||||
}
|
||||
|
||||
eclipse.classpath.file.whenMerged { classpath ->
|
||||
classpath.entries.removeAll { it.path =~ /src\/(main|test)\/java\d+/ }
|
||||
def baseline = eclipseJavaBaseline()
|
||||
|
||||
// Remove Gradle output for multi-release source sets, such as
|
||||
// "build/classes/java/java21".
|
||||
classpath.entries.removeAll { it.path =~ /build\/classes\/[^\/]+\/java\d+(Test)?$/ }
|
||||
|
||||
// Remove classpath entries for multi-release source folders above the baseline.
|
||||
classpath.entries.removeAll {
|
||||
it instanceof SourceFolder && (javaVersionOf(it) ?: 0) > baseline
|
||||
}
|
||||
|
||||
// Mark multi-release test source folders (such as "src/test/java21") as test
|
||||
// sources, since they share the output folder with "src/test/java".
|
||||
classpath.entries.findAll { it instanceof SourceFolder && it.path ==~ /src\/test\/java\d+/ }.each {
|
||||
it.entryAttributes['test'] = 'true'
|
||||
}
|
||||
|
||||
// Exclude types from lower source folders which are overridden in higher ones.
|
||||
['main', 'test'].each { scope ->
|
||||
def sourceFolders = classpath.entries.findAll {
|
||||
it instanceof SourceFolder && it.path.startsWith("src/${scope}/") &&
|
||||
javaVersionOf(it) != null
|
||||
}
|
||||
sourceFolders.each { folder ->
|
||||
def overriddenTypes = sourceFolders
|
||||
.findAll { javaVersionOf(it) > javaVersionOf(folder) }
|
||||
.collectMany { relativeJavaFiles(it.path) }
|
||||
.findAll { file("${folder.path}/${it}").exists() }
|
||||
if (!overriddenTypes.isEmpty()) {
|
||||
folder.excludes = (folder.excludes + overriddenTypes).unique()
|
||||
}
|
||||
}
|
||||
|
||||
// Place higher source folders before lower ones, so that the debugger's source
|
||||
// lookup finds overriding types before excluded ones.
|
||||
def multiReleaseFolders = sourceFolders.findAll { javaVersionOf(it) > 0 }
|
||||
.sort { -javaVersionOf(it) }
|
||||
def baseFolder = sourceFolders.find { javaVersionOf(it) == 0 }
|
||||
if (baseFolder != null && !multiReleaseFolders.isEmpty()) {
|
||||
classpath.entries.removeAll(multiReleaseFolders)
|
||||
classpath.entries.addAll(classpath.entries.indexOf(baseFolder), multiReleaseFolders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove classpath entries for non-existent libraries added by the multiReleaseJar
|
||||
|
||||
@@ -53,11 +53,15 @@ within your locally cloned `spring-framework` working directory._
|
||||
compile `spring-core` and generate JAXB types for `spring-oxm`.
|
||||
1. `spring-aspects` does not compile due to references to aspect types unknown to Eclipse.
|
||||
- If you installed _AJDT_ into Eclipse it should work.
|
||||
1. The Java 21 and Java 24 multi-release sources in `spring-core` (`src/main/java21`,
|
||||
`src/main/java24`, and `src/test/java21`) are not configured as source folders in
|
||||
Eclipse, since an Eclipse project supports only a single Java compliance level.
|
||||
- Use `./gradlew :spring-core:java21Test` or `./gradlew :spring-core:java24Test` to
|
||||
build and test those sources from the command line.
|
||||
1. Since an Eclipse project supports only a single Java compliance level, `spring-core`
|
||||
is configured with a Java 24 baseline in Eclipse, which includes the Java 21 and
|
||||
Java 24 multi-release sources (`src/main/java21`, `src/main/java24`, and
|
||||
`src/test/java21`). Types overridden by those sources are excluded from
|
||||
`src/main/java`. Eclipse does not report usage of Java features newer than the
|
||||
project-wide Java 17 baseline; however, such usage will be caught by the Gradle build.
|
||||
- To work on the Java 17 or Java 21 variants instead, run
|
||||
`./gradlew eclipse -PeclipseJavaBaseline=17` (or `21`) and refresh the projects in
|
||||
Eclipse (or close and reopen them if the compiler settings are not updated).
|
||||
1. While JUnit tests pass from the command line with Gradle, some may fail when run from
|
||||
the IDE.
|
||||
- Resolving this is a work in progress.
|
||||
|
||||
Reference in New Issue
Block a user