Improve classpath extraction from classloader:

- implement opt-in unpacking/caching of the jar collection archives,
  such as spring boot fat jars and WARs, to the temp dir, and creating
  a valid classpath from extracted archive
- turning it on for the new default jsr223 engine
- fallback to extracting classpath from resource URLs if the classloader
  is not known url-based one
- refactor and optimize extraction
- cache the last retrieved classpath in the default JSR-223 script engine
  factory
This commit is contained in:
Ilya Chernikov
2019-05-28 19:18:13 +02:00
parent e95569a273
commit f986856d03
6 changed files with 252 additions and 65 deletions
@@ -0,0 +1,62 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package kotlin.script.experimental.jvmhost.test
import junit.framework.TestCase
import org.junit.Assert
import org.junit.Test
import java.io.File
import java.io.FileOutputStream
import java.net.URLClassLoader
import java.util.jar.JarEntry
import java.util.jar.JarOutputStream
import kotlin.script.experimental.jvm.util.classpathFromClassloader
class ClassPathTest : TestCase() {
@Test
fun testExtractFromFat() {
val collection = createTempFile("col", ".jar").apply { createCollectionJar(emulatedCollectionFiles, "BOOT-INF") }
val cl = URLClassLoader(arrayOf(collection.toURI().toURL()), null)
val cp = classpathFromClassloader(cl, true)
Assert.assertTrue(cp != null && cp.isNotEmpty())
testUnpackedCollection(cp!!, emulatedCollectionFiles)
}
}
private val emulatedCollectionFiles = arrayOf(
"classes/a/b.class",
"lib/c-d.jar"
)
fun File.createCollectionJar(fileNames: Array<String>, infDirName: String) {
FileOutputStream(this).use { fileStream ->
val jarStream = JarOutputStream(fileStream)
jarStream.putNextEntry(JarEntry("$infDirName/classes/"))
jarStream.putNextEntry(JarEntry("$infDirName/lib/"))
for (name in fileNames) {
jarStream.putNextEntry(JarEntry("$infDirName/$name"))
jarStream.write(name.toByteArray())
}
jarStream.finish()
}
}
fun testUnpackedCollection(classpath: List<File>, fileNames: Array<String>) {
fun List<String>.checkFiles(root: File) = forEach {
val file = File(root, it)
Assert.assertTrue(file.exists())
Assert.assertEquals(it, file.readText())
}
val (classes, jars) = fileNames.partition { it.startsWith("classes") }
val (cpClasses, cpJars) = classpath.partition { it.isDirectory && it.name == "classes" }
Assert.assertTrue(cpClasses.size == 1)
classes.checkFiles(cpClasses.first().parentFile)
jars.checkFiles(cpJars.first().parentFile.parentFile)
}