CLI: load module-info from META-INF/versions/... for any version
Not just 9, since at least some libraries are putting module-info to META-INF/versions/11 nowadays. #KT-48027 Fixed
This commit is contained in:
@@ -156,13 +156,11 @@ class ClasspathRootsResolver(
|
|||||||
|
|
||||||
private fun modularBinaryRoot(root: VirtualFile): JavaModule? {
|
private fun modularBinaryRoot(root: VirtualFile): JavaModule? {
|
||||||
val isJar = root.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL
|
val isJar = root.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL
|
||||||
val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) }
|
val manifest = lazy(NONE) { readManifestAttributes(root) }
|
||||||
|
|
||||||
val moduleInfoFile =
|
val moduleInfoFile =
|
||||||
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
|
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
|
||||||
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
|
?: if (isJar) tryLoadVersionSpecificModuleInfo(root, manifest) else null
|
||||||
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moduleInfoFile != null) {
|
if (moduleInfoFile != null) {
|
||||||
val moduleInfo = JavaModuleInfo.read(moduleInfoFile, javaFileManager, searchScope) ?: return null
|
val moduleInfo = JavaModuleInfo.read(moduleInfoFile, javaFileManager, searchScope) ?: return null
|
||||||
@@ -173,7 +171,7 @@ class ClasspathRootsResolver(
|
|||||||
if (isJar) {
|
if (isJar) {
|
||||||
val moduleRoot = listOf(JavaModule.Root(root, isBinary = true))
|
val moduleRoot = listOf(JavaModule.Root(root, isBinary = true))
|
||||||
|
|
||||||
val automaticModuleName = manifest?.getValue(AUTOMATIC_MODULE_NAME)
|
val automaticModuleName = manifest.value?.getValue(AUTOMATIC_MODULE_NAME)
|
||||||
if (automaticModuleName != null) {
|
if (automaticModuleName != null) {
|
||||||
return JavaModule.Automatic(automaticModuleName, moduleRoot)
|
return JavaModule.Automatic(automaticModuleName, moduleRoot)
|
||||||
}
|
}
|
||||||
@@ -190,6 +188,23 @@ class ClasspathRootsResolver(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun tryLoadVersionSpecificModuleInfo(root: VirtualFile, manifest: Lazy<Attributes?>): VirtualFile? {
|
||||||
|
val versionsDir = root.findChild("META-INF")?.findChild("versions") ?: return null
|
||||||
|
|
||||||
|
val isMultiReleaseJar = manifest.value?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true)
|
||||||
|
if (isMultiReleaseJar != true) return null
|
||||||
|
|
||||||
|
val versions = versionsDir.children.filter {
|
||||||
|
val version = it.name.toIntOrNull()
|
||||||
|
version != null && version >= 9
|
||||||
|
}.sortedBy { it.name.toInt() }
|
||||||
|
for (version in versions) {
|
||||||
|
val file = version.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
|
||||||
|
if (file != null) return file
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
private fun readManifestAttributes(jarRoot: VirtualFile): Attributes? {
|
private fun readManifestAttributes(jarRoot: VirtualFile): Attributes? {
|
||||||
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
|
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
|
||||||
return try {
|
return try {
|
||||||
@@ -323,7 +338,6 @@ class ClasspathRootsResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val MULTI_RELEASE_MODULE_INFO_CLS_FILE = "META-INF/versions/9/${PsiJavaModule.MODULE_INFO_CLS_FILE}"
|
|
||||||
const val AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"
|
const val AUTOMATIC_MODULE_NAME = "Automatic-Module-Name"
|
||||||
const val IS_MULTI_RELEASE = "Multi-Release"
|
const val IS_MULTI_RELEASE = "Multi-Release"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.test.util.KtTestUtil
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import java.util.jar.Manifest
|
import java.util.jar.Manifest
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
class Java11ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
class Java11ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
||||||
override val testDataPath: String
|
override val testDataPath: String
|
||||||
@@ -78,13 +79,13 @@ class Java11ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createMultiReleaseJar(jdk9Home: File, destination: File, mainRoot: File, java9Root: File): File {
|
private fun createMultiReleaseJar(jdkHome: File, destination: File, mainRoot: File, version: Int, versionSpecificRoot: File): File {
|
||||||
val command = listOf<String>(
|
val command = listOf<String>(
|
||||||
File(jdk9Home, "bin/jar").path,
|
File(jdkHome, "bin/jar").path,
|
||||||
"--create", "--file=$destination",
|
"--create", "--file=$destination",
|
||||||
"-C", mainRoot.path, ".",
|
"-C", mainRoot.path, ".",
|
||||||
"--release", "9",
|
"--release", version.toString(),
|
||||||
"-C", java9Root.path, "."
|
"-C", versionSpecificRoot.path, "."
|
||||||
)
|
)
|
||||||
|
|
||||||
val process = ProcessBuilder().command(command).inheritIO().start()
|
val process = ProcessBuilder().command(command).inheritIO().start()
|
||||||
@@ -124,8 +125,7 @@ class Java11ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
|||||||
fun testAllModulePathAndNamedModule() {
|
fun testAllModulePathAndNamedModule() {
|
||||||
try {
|
try {
|
||||||
module("main", addModules = listOf("ALL-MODULE-PATH"))
|
module("main", addModules = listOf("ALL-MODULE-PATH"))
|
||||||
}
|
} catch (e: JavaCompilationError) {
|
||||||
catch (e: JavaCompilationError) {
|
|
||||||
// Java compilation should fail, it's expected
|
// Java compilation should fail, it's expected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,10 +176,10 @@ class Java11ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
|||||||
"-Xmodule-path=${a.path}"
|
"-Xmodule-path=${a.path}"
|
||||||
)
|
)
|
||||||
compileLibrary(
|
compileLibrary(
|
||||||
"moduleB",
|
"moduleB",
|
||||||
additionalOptions = kotlinOptions,
|
additionalOptions = kotlinOptions,
|
||||||
compileJava = { _, _, _ -> error("No .java files in moduleB in this test") },
|
compileJava = { _, _, _ -> error("No .java files in moduleB in this test") },
|
||||||
checkKotlinOutput = checkKotlinOutput("moduleB")
|
checkKotlinOutput = checkKotlinOutput("moduleB")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,12 +192,17 @@ class Java11ModulesIntegrationTest : AbstractKotlinCompilerIntegrationTest() {
|
|||||||
libraryOut11.mkdirs()
|
libraryOut11.mkdirs()
|
||||||
File(libraryOut, "module-info.class").renameTo(File(libraryOut11, "module-info.class"))
|
File(libraryOut, "module-info.class").renameTo(File(libraryOut11, "module-info.class"))
|
||||||
|
|
||||||
// Use the name other from 'library' to prevent it from being loaded as an automatic module if module-info.class is not found
|
for (version in listOf(9, 10, 11)) {
|
||||||
val libraryJar = createMultiReleaseJar(
|
try {
|
||||||
KtTestUtil.getJdk11Home(), File(tmpdir, "multi-release-library.jar"), libraryOut, libraryOut11
|
// Use the name other from 'library' to prevent it from being loaded as an automatic module if module-info.class is not found.
|
||||||
)
|
val libraryJar = createMultiReleaseJar(
|
||||||
|
KtTestUtil.getJdk11Home(), File(tmpdir, "multi-release-library-jdk$version.jar"), libraryOut, version, libraryOut11
|
||||||
module("main", listOf(libraryJar))
|
)
|
||||||
|
module("main", listOf(libraryJar))
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
fail("Fail on testing that module-info.class is loaded from META-INF/versions/$version", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun testAutomaticModuleNames() {
|
fun testAutomaticModuleNames() {
|
||||||
|
|||||||
Reference in New Issue
Block a user