mirror of
https://github.com/corda/corda.git
synced 2024-12-24 07:06:44 +00:00
CORDA-1274: Migrated usage of FastClasspathScanner to ClassGraph (#4060)
FastClasspathScanner was renamed to ClassGraph for the version 4 release
This commit is contained in:
parent
8c41ae208d
commit
aced03df54
@ -68,7 +68,7 @@ buildscript {
|
||||
ext.commons_cli_version = '1.4'
|
||||
ext.protonj_version = '0.27.1' // This is now aligned with the Artemis version, but retaining in case we ever need to diverge again for a bug fix.
|
||||
ext.snappy_version = '0.4'
|
||||
ext.fast_classpath_scanner_version = '2.12.3'
|
||||
ext.class_graph_version = '4.2.12'
|
||||
ext.jcabi_manifests_version = '1.1'
|
||||
ext.picocli_version = '3.5.2'
|
||||
|
||||
|
@ -36,8 +36,8 @@ dependencies {
|
||||
compile "org.ow2.asm:asm-tree:$asm_version"
|
||||
compile "org.ow2.asm:asm-commons:$asm_version"
|
||||
|
||||
// Classpath scanner
|
||||
shadow "io.github.lukehutch:fast-classpath-scanner:$fast_classpath_scanner_version"
|
||||
// ClassGraph: classpath scanning
|
||||
shadow "io.github.classgraph:classgraph:$class_graph_version"
|
||||
|
||||
// Test utilities
|
||||
testCompile "junit:junit:$junit_version"
|
||||
|
@ -1,8 +1,9 @@
|
||||
@file:JvmName("Utilities")
|
||||
package net.corda.djvm.tools.cli
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import java.lang.reflect.Modifier
|
||||
import io.github.classgraph.ClassGraph
|
||||
import java.lang.reflect.Modifier.isAbstract
|
||||
import java.lang.reflect.Modifier.isStatic
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
@ -92,13 +93,10 @@ val userClassPath: String = System.getProperty("java.class.path")
|
||||
* Get a reference of each concrete class that implements interface or class [T].
|
||||
*/
|
||||
inline fun <reified T> find(scanSpec: String = "net/corda/djvm"): List<Class<*>> {
|
||||
val references = mutableListOf<Class<*>>()
|
||||
FastClasspathScanner(scanSpec)
|
||||
.matchClassesImplementing(T::class.java) { clazz ->
|
||||
if (!Modifier.isAbstract(clazz.modifiers) && !Modifier.isStatic(clazz.modifiers)) {
|
||||
references.add(clazz)
|
||||
}
|
||||
}
|
||||
return ClassGraph()
|
||||
.whitelistPaths(scanSpec)
|
||||
.enableAllInfo()
|
||||
.scan()
|
||||
return references
|
||||
.use { it.getClassesImplementing(T::class.java.name).loadClasses(T::class.java) }
|
||||
.filter { !isAbstract(it.modifiers) && !isStatic(it.modifiers) }
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.corda.djvm.utilities
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.classgraph.ClassGraph
|
||||
import java.lang.reflect.Modifier
|
||||
|
||||
/**
|
||||
@ -13,19 +13,19 @@ object Discovery {
|
||||
* Get an instance of each concrete class that implements interface or class [T].
|
||||
*/
|
||||
inline fun <reified T> find(): List<T> {
|
||||
val instances = mutableListOf<T>()
|
||||
FastClasspathScanner("net/corda/djvm")
|
||||
.matchClassesImplementing(T::class.java) { clazz ->
|
||||
if (clazz.modifiers and FORBIDDEN_CLASS_MASK == 0) {
|
||||
try {
|
||||
instances.add(clazz.newInstance())
|
||||
} catch (exception: Throwable) {
|
||||
throw Exception("Unable to instantiate ${clazz.name}", exception)
|
||||
}
|
||||
return ClassGraph()
|
||||
.whitelistPaths("net/corda/djvm")
|
||||
.enableAllInfo()
|
||||
.scan()
|
||||
.use { it.getClassesImplementing(T::class.java.name).loadClasses(T::class.java) }
|
||||
.filter { it.modifiers and FORBIDDEN_CLASS_MASK == 0 }
|
||||
.map {
|
||||
try {
|
||||
it.newInstance()
|
||||
} catch (exception: Throwable) {
|
||||
throw Exception("Unable to instantiate ${it.name}", exception)
|
||||
}
|
||||
}
|
||||
.scan()
|
||||
return instances
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -51,8 +51,8 @@ dependencies {
|
||||
// JOptSimple: command line option parsing
|
||||
compile "net.sf.jopt-simple:jopt-simple:$jopt_simple_version"
|
||||
|
||||
// FastClasspathScanner: classpath scanning
|
||||
compile "io.github.lukehutch:fast-classpath-scanner:$fast_classpath_scanner_version"
|
||||
// ClassGraph: classpath scanning
|
||||
compile "io.github.classgraph:classgraph:$class_graph_version"
|
||||
|
||||
compile "commons-io:commons-io:$commonsio_version"
|
||||
compile "com.spotify:docker-client:$docker_client_version"
|
||||
|
@ -1,27 +1,29 @@
|
||||
package net.corda.behave.scenarios
|
||||
|
||||
import cucumber.api.java8.En
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.classgraph.ClassGraph
|
||||
import net.corda.behave.scenarios.api.StepsBlock
|
||||
import net.corda.behave.scenarios.api.StepsProvider
|
||||
import net.corda.behave.scenarios.steps.*
|
||||
import net.corda.core.internal.objectOrNewInstance
|
||||
import net.corda.core.utilities.loggerFor
|
||||
import net.corda.core.utilities.contextLogger
|
||||
|
||||
@Suppress("KDocMissingDocumentation")
|
||||
class StepsContainer(val state: ScenarioState) : En {
|
||||
|
||||
companion object {
|
||||
private val log = contextLogger()
|
||||
|
||||
val stepsProviders: List<StepsProvider> by lazy {
|
||||
FastClasspathScanner().addClassLoader(this::class.java.classLoader).scan()
|
||||
.getNamesOfClassesImplementing(StepsProvider::class.java)
|
||||
.mapNotNull { this::class.java.classLoader.loadClass(it).asSubclass(StepsProvider::class.java) }
|
||||
ClassGraph()
|
||||
.addClassLoader(this::class.java.classLoader)
|
||||
.enableAllInfo()
|
||||
.scan()
|
||||
.use { it.getClassesImplementing(StepsProvider::class.java.name).loadClasses(StepsProvider::class.java) }
|
||||
.map { it.kotlin.objectOrNewInstance() }
|
||||
}
|
||||
}
|
||||
|
||||
private val log = loggerFor<StepsContainer>()
|
||||
|
||||
private val stepDefinitions: List<StepsBlock> = listOf(
|
||||
CashSteps(),
|
||||
ConfigurationSteps(),
|
||||
|
@ -27,8 +27,8 @@ dependencies {
|
||||
|
||||
compile "org.apache.qpid:proton-j:$protonj_version"
|
||||
|
||||
// FastClasspathScanner: classpath scanning - needed for the NetworkBootstrapper.
|
||||
compile "io.github.lukehutch:fast-classpath-scanner:$fast_classpath_scanner_version"
|
||||
// ClassGraph: classpath scanning
|
||||
compile "io.github.classgraph:classgraph:$class_graph_version"
|
||||
|
||||
// For caches rather than guava
|
||||
compile "com.github.ben-manes.caffeine:caffeine:$caffeine_version"
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.corda.nodeapi.internal
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.classgraph.ClassGraph
|
||||
import net.corda.core.contracts.Contract
|
||||
import net.corda.core.contracts.ContractClassName
|
||||
import net.corda.core.contracts.UpgradedContract
|
||||
@ -28,15 +28,13 @@ class ContractsJarFile(private val file: Path) : ContractsJar {
|
||||
override val hash: SecureHash by lazy(LazyThreadSafetyMode.NONE, file::hash)
|
||||
|
||||
override fun scan(): List<ContractClassName> {
|
||||
val scanResult = FastClasspathScanner()
|
||||
// A set of a single element may look odd, but if this is removed "Path" which itself is an `Iterable`
|
||||
// is getting broken into pieces to scan individually, which doesn't yield desired effect.
|
||||
.overrideClasspath(singleton(file))
|
||||
.scan()
|
||||
val scanResult = ClassGraph().overrideClasspath(singleton(file)).enableAllInfo().scan()
|
||||
|
||||
val contractClassNames = coreContractClasses
|
||||
.flatMap { scanResult.getNamesOfClassesImplementing(it.qualifiedName) }
|
||||
.toSet()
|
||||
val contractClassNames = scanResult.use {
|
||||
coreContractClasses
|
||||
.flatMap { scanResult.getClassesImplementing(it.qualifiedName).names }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
return URLClassLoader(arrayOf(file.toUri().toURL()), Contract::class.java.classLoader).use { cl ->
|
||||
contractClassNames.mapNotNull {
|
||||
|
@ -1,7 +1,7 @@
|
||||
package net.corda.node.internal.cordapp
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.lukehutch.fastclasspathscanner.scanner.ScanResult
|
||||
import io.github.classgraph.ClassGraph
|
||||
import io.github.classgraph.ScanResult
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.crypto.SecureHash
|
||||
import net.corda.core.crypto.sha256
|
||||
@ -95,7 +95,7 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
||||
}
|
||||
private fun loadCordapps(): List<CordappImpl> {
|
||||
val cordapps = cordappJarPaths
|
||||
.map { scanCordapp(it).toCordapp(it) }
|
||||
.map { url -> scanCordapp(url).use { it.toCordapp(url) } }
|
||||
.filter {
|
||||
if (it.info.minimumPlatformVersion > versionInfo.platformVersion) {
|
||||
logger.warn("Not loading CorDapp ${it.info.shortName} (${it.info.vendor}) as it requires minimum " +
|
||||
@ -202,7 +202,8 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
||||
private fun scanCordapp(cordappJarPath: RestrictedURL): RestrictedScanResult {
|
||||
logger.info("Scanning CorDapp in ${cordappJarPath.url}")
|
||||
return cachedScanResult.computeIfAbsent(cordappJarPath) {
|
||||
RestrictedScanResult(FastClasspathScanner().addClassLoader(appClassLoader).overrideClasspath(cordappJarPath.url).scan(), cordappJarPath.qualifiedNamePrefix)
|
||||
val scanResult = ClassGraph().addClassLoader(appClassLoader).overrideClasspath(cordappJarPath.url).enableAllInfo().scan()
|
||||
RestrictedScanResult(scanResult, cordappJarPath.qualifiedNamePrefix)
|
||||
}
|
||||
}
|
||||
|
||||
@ -239,40 +240,49 @@ class JarScanningCordappLoader private constructor(private val cordappJarPaths:
|
||||
return map { it.kotlin.objectOrNewInstance() }
|
||||
}
|
||||
|
||||
private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) {
|
||||
private inner class RestrictedScanResult(private val scanResult: ScanResult, private val qualifiedNamePrefix: String) : AutoCloseable {
|
||||
fun getNamesOfClassesImplementing(type: KClass<*>): List<String> {
|
||||
return scanResult.getNamesOfClassesImplementing(type.java)
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
return scanResult.getClassesImplementing(type.java.name).names.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
}
|
||||
|
||||
fun <T : Any> getClassesWithSuperclass(type: KClass<T>): List<Class<out T>> {
|
||||
return scanResult.getNamesOfSubclassesOf(type.java)
|
||||
return scanResult
|
||||
.getSubclasses(type.java.name)
|
||||
.names
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
.filterNot { it.isAbstractClass }
|
||||
}
|
||||
|
||||
fun <T : Any> getClassesImplementing(type: KClass<T>): List<T> {
|
||||
return scanResult.getNamesOfClassesImplementing(type.java)
|
||||
return scanResult
|
||||
.getClassesImplementing(type.java.name)
|
||||
.names
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
.filterNot { it.isAbstractClass }
|
||||
.map { it.kotlin.objectOrNewInstance() }
|
||||
}
|
||||
|
||||
fun <T : Any> getClassesWithAnnotation(type: KClass<T>, annotation: KClass<out Annotation>): List<Class<out T>> {
|
||||
return scanResult.getNamesOfClassesWithAnnotation(annotation.java)
|
||||
return scanResult
|
||||
.getClassesWithAnnotation(annotation.java.name)
|
||||
.names
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
}
|
||||
|
||||
fun <T : Any> getConcreteClassesOfType(type: KClass<T>): List<Class<out T>> {
|
||||
return scanResult.getNamesOfSubclassesOf(type.java)
|
||||
return scanResult
|
||||
.getSubclasses(type.java.name)
|
||||
.names
|
||||
.filter { it.startsWith(qualifiedNamePrefix) }
|
||||
.mapNotNull { loadClass(it, type) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
.filterNot { it.isAbstractClass }
|
||||
}
|
||||
|
||||
override fun close() = scanResult.close()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,8 @@ dependencies {
|
||||
// For AMQP serialisation.
|
||||
compile "org.apache.qpid:proton-j:$protonj_version"
|
||||
|
||||
// FastClasspathScanner: classpath scanning
|
||||
compile "io.github.lukehutch:fast-classpath-scanner:$fast_classpath_scanner_version"
|
||||
// ClassGraph: classpath scanning
|
||||
compile "io.github.classgraph:classgraph:$class_graph_version"
|
||||
|
||||
// Pure-Java Snappy compression
|
||||
compile "org.iq80.snappy:snappy:$snappy_version"
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
package net.corda.serialization.internal.amqp
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.classgraph.ClassGraph
|
||||
import net.corda.core.DeleteForDJVM
|
||||
import net.corda.core.KeepForDJVM
|
||||
import net.corda.core.StubOutForDJVM
|
||||
import net.corda.core.cordapp.Cordapp
|
||||
import net.corda.core.internal.isAbstractClass
|
||||
import net.corda.core.internal.objectOrNewInstance
|
||||
import net.corda.core.internal.uncheckedCast
|
||||
import net.corda.core.serialization.*
|
||||
@ -16,7 +17,6 @@ import net.corda.serialization.internal.CordaSerializationMagic
|
||||
import net.corda.serialization.internal.DefaultWhitelist
|
||||
import net.corda.serialization.internal.MutableClassWhitelist
|
||||
import net.corda.serialization.internal.SerializationScheme
|
||||
import java.lang.reflect.Modifier
|
||||
import java.util.*
|
||||
|
||||
val AMQP_ENABLED get() = SerializationDefaults.P2P_CONTEXT.preferredSerializationVersion == amqpMagic
|
||||
@ -72,10 +72,16 @@ abstract class AbstractAMQPSerializationScheme(
|
||||
@StubOutForDJVM
|
||||
private fun scanClasspathForSerializers(scanSpec: String): List<SerializationCustomSerializer<*, *>> =
|
||||
this::class.java.classLoader.let { cl ->
|
||||
FastClasspathScanner(scanSpec).addClassLoader(cl).scan()
|
||||
.getNamesOfClassesImplementing(SerializationCustomSerializer::class.java)
|
||||
.map { cl.loadClass(it).asSubclass(SerializationCustomSerializer::class.java) }
|
||||
.filterNot { Modifier.isAbstract(it.modifiers) }
|
||||
ClassGraph()
|
||||
.whitelistPackages(scanSpec)
|
||||
.addClassLoader(cl)
|
||||
.enableAllInfo()
|
||||
.scan()
|
||||
.use {
|
||||
val serializerClass = SerializationCustomSerializer::class.java
|
||||
it.getClassesImplementing(serializerClass.name).loadClasses(serializerClass)
|
||||
}
|
||||
.filterNot { it.isAbstractClass }
|
||||
.map { it.kotlin.objectOrNewInstance() }
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
package net.corda.testing.node.internal
|
||||
|
||||
import io.github.lukehutch.fastclasspathscanner.FastClasspathScanner
|
||||
import io.github.classgraph.ClassGraph
|
||||
import net.corda.core.internal.createDirectories
|
||||
import net.corda.core.internal.deleteIfExists
|
||||
import net.corda.core.internal.outputStream
|
||||
@ -69,9 +69,12 @@ fun Iterable<TestCorDapp>.packageInDirectory(directory: Path) {
|
||||
* Returns all classes within the [targetPackage].
|
||||
*/
|
||||
fun allClassesForPackage(targetPackage: String): Set<Class<*>> {
|
||||
|
||||
val scanResult = FastClasspathScanner(targetPackage).strictWhitelist().scan()
|
||||
return scanResult.namesOfAllClasses.filter { className -> className.startsWith(targetPackage) }.map(scanResult::classNameToClassRef).toSet()
|
||||
return ClassGraph()
|
||||
.whitelistPackages(targetPackage)
|
||||
.enableAllInfo()
|
||||
.scan()
|
||||
.use { it.allClasses.loadClasses() }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user