Skip to content

Commit 468101f

Browse files
authored
Fix decoding of classloader resources (#234)
* Fix decoding of classloader resources * Document internal method * Fix paths on Windows
1 parent 4582521 commit 468101f

File tree

2 files changed

+38
-9
lines changed

2 files changed

+38
-9
lines changed

core/src/main/kotlin/com/tschuchort/compiletesting/AbstractKotlinCompilation.kt

+16-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import java.io.File
2020
import java.io.OutputStream
2121
import java.io.PrintStream
2222
import java.net.URI
23+
import java.net.URL
2324
import java.nio.file.Files
25+
import java.nio.file.Path
2426
import java.nio.file.Paths
2527

2628
/**
@@ -239,23 +241,26 @@ abstract class AbstractKotlinCompilation<A : CommonCompilerArguments> internal c
239241
}
240242

241243
protected fun getResourcesPath(): String {
242-
val resourceName = "META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar"
243244
return this::class.java.classLoader.getResources(resourceName)
244245
.asSequence()
245-
.mapNotNull { url ->
246-
val uri = URI.create(url.toString().removeSuffix("/$resourceName"))
247-
when (uri.scheme) {
248-
"jar" -> Paths.get(URI.create(uri.schemeSpecificPart.removeSuffix("!")))
249-
"file" -> Paths.get(uri)
250-
else -> return@mapNotNull null
251-
}.toAbsolutePath()
252-
}
246+
.mapNotNull { url -> urlToResourcePath(url) }
253247
.find { resourcesPath ->
254248
ServiceLoaderLite.findImplementations(ComponentRegistrar::class.java, listOf(resourcesPath.toFile()))
255249
.any { implementation -> implementation == MainComponentRegistrar::class.java.name }
256250
}?.toString() ?: throw AssertionError("Could not get path to ComponentRegistrar service from META-INF")
257251
}
258252

253+
/** Maps a URL resource for a class from a JAR or file to an absolute Path on disk */
254+
internal fun urlToResourcePath(url: URL): Path? {
255+
val uri = url.toURI()
256+
val uriPath = when (uri.scheme) {
257+
"jar" -> uri.rawSchemeSpecificPart.removeSuffix("!/$resourceName")
258+
"file" -> uri.toString().removeSuffix("/$resourceName")
259+
else -> return null
260+
}
261+
return Paths.get(URI.create(uriPath)).toAbsolutePath()
262+
}
263+
259264
/** Searches compiler log for known errors that are hard to debug for the user */
260265
protected fun searchSystemOutForKnownErrors(compilerSystemOut: String) {
261266
if (compilerSystemOut.contains("No enum constant com.sun.tools.javac.main.Option.BOOT_CLASS_PATH")) {
@@ -306,6 +311,8 @@ abstract class AbstractKotlinCompilation<A : CommonCompilerArguments> internal c
306311
protected fun error(s: String) = internalMessageStream.println("error: $s")
307312

308313
internal val internalMessageStreamAccess: PrintStream get() = internalMessageStream
314+
315+
private val resourceName = "META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar"
309316
}
310317

311318
@ExperimentalCompilerApi

core/src/test/kotlin/com/tschuchort/compiletesting/CompilerPluginsTest.kt

+22
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
88
import org.junit.Assert
99
import org.junit.Test
1010
import org.mockito.Mockito
11+
import java.net.URL
1112
import javax.annotation.processing.AbstractProcessor
1213
import javax.annotation.processing.RoundEnvironment
1314
import javax.lang.model.element.TypeElement
@@ -71,5 +72,26 @@ class CompilerPluginsTest {
7172

7273
assertThat(result.exitCode).isEqualTo(KotlinCompilation.ExitCode.OK)
7374
}
75+
76+
@Test
77+
fun `convert jar url resource to path without decoding encoded path`() {
78+
// path on disk has "url%3Aport" path segment, but it's encoded from classLoader.getResources()
79+
val absolutePath = "jar:file:/path/to/jar/url%253Aport/core-0.4.0.jar!" +
80+
"/META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar"
81+
val resultPath = KotlinCompilation().urlToResourcePath(URL(absolutePath)).toString()
82+
assertThat(resultPath.contains("url:")).isFalse()
83+
assertThat(resultPath.contains("url%25")).isFalse()
84+
assertThat(resultPath.contains("url%3A")).isTrue()
85+
}
86+
87+
@Test
88+
fun `convert file url resource to path without decoding`() {
89+
// path on disk has "repos%3Aoss" path segment, but it's encoded from classLoader.getResources()
90+
val absolutePath = "file:/Users/user/repos%253Aoss/kotlin-compile-testing/core/build/resources/main"
91+
val resultPath = KotlinCompilation().urlToResourcePath(URL(absolutePath)).toString()
92+
assertThat(resultPath.contains("repos:")).isFalse()
93+
assertThat(resultPath.contains("repos%25")).isFalse()
94+
assertThat(resultPath.contains("repos%3A")).isTrue()
95+
}
7496
}
7597

0 commit comments

Comments
 (0)