Check 'Multi-Release' manifest attribute value for multi-release jars

See http://openjdk.java.net/jeps/238
This commit is contained in:
Alexander Udalov
2017-07-05 16:27:44 +03:00
parent 7ab018da7b
commit 0f06140a3d
2 changed files with 26 additions and 13 deletions
@@ -42,7 +42,9 @@ import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleGraph
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
import java.io.File
import java.io.IOException
import java.util.jar.Attributes
import java.util.jar.Manifest
import kotlin.LazyThreadSafetyMode.NONE
internal class ClasspathRootsResolver(
private val psiManager: PsiManager,
@@ -111,26 +113,25 @@ internal class ClasspathRootsResolver(
}
private fun modularBinaryRoot(root: VirtualFile, originalFile: File): JavaModule? {
val isJar = root.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL
val manifest: Attributes? by lazy(NONE) { readManifestAttributes(root) }
val moduleInfoFile =
root.findChild(PsiJavaModule.MODULE_INFO_CLS_FILE)
?: root.takeIf { it.fileSystem.protocol == StandardFileSystems.JAR_PROTOCOL }
?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)
?: root.takeIf { isJar }?.findFileByRelativePath(MULTI_RELEASE_MODULE_INFO_CLS_FILE)?.takeIf {
manifest?.getValue(IS_MULTI_RELEASE)?.equals("true", ignoreCase = true) == true
}
if (moduleInfoFile != null) {
val moduleInfo = JavaModuleInfo.read(moduleInfoFile) ?: return null
return JavaModule.Explicit(moduleInfo, root, moduleInfoFile, isBinary = true)
}
// Only .jar files can be automatic modules
if (originalFile.extension == StandardFileSystems.JAR_PROTOCOL) {
val manifestFile = root.findChild("META-INF")?.findChild("MANIFEST.MF")
if (manifestFile != null) {
try {
val moduleName = Manifest(manifestFile.inputStream).mainAttributes.getValue(AUTOMATIC_MODULE_NAME)
return JavaModule.Automatic(moduleName, root)
}
catch (e: IOException) {
return null
}
if (isJar) {
val automaticModuleName = manifest?.getValue(AUTOMATIC_MODULE_NAME)
if (automaticModuleName != null) {
return JavaModule.Automatic(automaticModuleName, root)
}
val moduleName = LightJavaModule.moduleName(originalFile.nameWithoutExtension)
@@ -144,6 +145,16 @@ internal class ClasspathRootsResolver(
return null
}
private fun readManifestAttributes(jarRoot: VirtualFile): Attributes? {
val manifestFile = jarRoot.findChild("META-INF")?.findChild("MANIFEST.MF")
return try {
manifestFile?.inputStream?.let(::Manifest)?.mainAttributes
}
catch (e: IOException) {
null
}
}
private fun addModularRoots(modules: List<JavaModule>, result: MutableList<JavaRoot>) {
val sourceModules = modules.filterIsInstance<JavaModule.Explicit>().filterNot(JavaModule::isBinary)
if (sourceModules.size > 1) {
@@ -256,5 +267,6 @@ internal class ClasspathRootsResolver(
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 IS_MULTI_RELEASE = "Multi-Release"
}
}