Skip to content

Commit 4a74858

Browse files
committed
Optimized reflections utils
1 parent 5bfeab0 commit 4a74858

File tree

6 files changed

+55
-65
lines changed

6 files changed

+55
-65
lines changed

common/src/main/kotlin/com/lambda/command/CommandRegistry.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ object CommandRegistry : Configurable(LambdaConfig), Loadable {
3232
override val name = "command"
3333
val prefix by setting("prefix", ';')
3434

35-
val commands = getInstances<LambdaCommand> { forPackages("com.lambda.command.commands") }.toMutableList()
35+
val commands = getInstances<LambdaCommand>().toMutableList()
3636

3737
override fun load() = "Loaded ${commands.size} commands with ${dispatcher.root.children()} possible command paths."
3838

common/src/main/kotlin/com/lambda/core/Loader.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ object Loader {
3030
val runtime: String
3131
get() = "${(System.currentTimeMillis() - started).milliseconds}"
3232

33-
private val loadables = getInstances<Loadable> { forPackages("com.lambda") }
33+
private val loadables = getInstances<Loadable>()
3434

3535
fun initialize(): Long {
3636
ascii.split("\n").forEach { LOG.info(it) }

common/src/main/kotlin/com/lambda/interaction/construction/processing/ProcessorRegistry.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@ import net.minecraft.block.BlockState
2424
import net.minecraft.block.Blocks
2525

2626
object ProcessorRegistry : Loadable {
27-
private const val PROCESSOR_PACKAGE = "com.lambda.interaction.construction.processing.processors"
28-
private val processors = getInstances<PlacementProcessor> { forPackages(PROCESSOR_PACKAGE) }
27+
private val processors = getInstances<PlacementProcessor>()
2928
private val processorCache = mutableMapOf<BlockState, PreprocessingStep>()
3029

3130
override fun load() = "Loaded ${processors.size} pre processors"
@@ -41,4 +40,4 @@ object ProcessorRegistry : Loadable {
4140
override fun acceptState(state: BlockState) = true
4241
override fun preProcess(state: BlockState) = PreprocessingStep()
4342
}
44-
}
43+
}

common/src/main/kotlin/com/lambda/interaction/material/container/ContainerManager.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ object ContainerManager : Loadable {
4747
// ToDo: Filter containers based on a filter setting TaskFlowModule.inventory.accessEnderChest etc
4848
get() = compileContainers.filter { it !is EnderChestContainer } + runtimeContainers
4949

50-
private val compileContainers =
51-
getInstances<MaterialContainer> { forPackages("com.lambda.interaction.material.container") }
50+
private val compileContainers = getInstances<MaterialContainer>()
5251
private val runtimeContainers = mutableSetOf<MaterialContainer>()
5352

5453
private var lastInteractedBlockEntity: BlockEntity? = null

common/src/main/kotlin/com/lambda/module/ModuleRegistry.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import com.lambda.util.reflections.getInstances
2525
*/
2626
object ModuleRegistry : Loadable {
2727
override val priority = 1
28-
val modules = getInstances<Module> { forPackages("com.lambda.module.modules") }.toMutableList()
28+
val modules = getInstances<Module>().toMutableList()
2929

3030
val moduleNames: Set<String>
3131
get() = modules.map { it.name }.toSet()

common/src/main/kotlin/com/lambda/util/reflections/Reflections.kt

Lines changed: 49 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -17,77 +17,69 @@
1717

1818
package com.lambda.util.reflections
1919

20-
import com.lambda.Lambda.LOG
2120
import com.lambda.util.extension.isObject
2221
import com.lambda.util.extension.objectInstance
2322
import org.reflections.Reflections
2423
import org.reflections.util.ConfigurationBuilder
2524
import java.lang.reflect.Modifier
26-
import java.util.regex.Pattern
25+
import java.util.Objects
2726

28-
/**
29-
* Retrieves instances of objects of the specified type using a DSL configuration.
30-
*
31-
* @param T The type of objects to retrieve instances for.
32-
* @param block A DSL block used to configure the [ReflectionConfigDsl].
33-
* @return A [List] of object instances of type [T], or null if no instances can be found.
34-
*/
35-
inline fun <reified T : Any> getInstances(block: ReflectionConfigDsl.() -> Unit): List<T> =
36-
getInstances<T>(getConfiguration(block))
27+
val cache = mutableMapOf<Int, Reflections>()
3728

3829
/**
39-
* Retrieves instances of objects of the specified type using a provided configuration.
30+
* Retrieves all instances of the specified type `T`.
4031
*
41-
* @param T The type of objects to retrieve instances for.
42-
* @param config A pre-configured [ConfigurationBuilder].
43-
* @return A [List] of object instances of type [T], or null if no instances can be found.
44-
*/
45-
inline fun <reified T : Any> getInstances(config: ConfigurationBuilder): List<T> =
46-
getSubTypesOf<T>(config).mapNotNull { clazz: Class<*> ->
47-
if (!clazz.isInterface
48-
&& !clazz.isEnum
49-
&& !clazz.isAnnotation
50-
&& !clazz.isObject
51-
) clazz.constructors.filter { !Modifier.isAbstract(clazz.modifiers) }.firstOrNull { it.parameterCount == 0 }
52-
?.newInstance() as? T
53-
?: null.also { LOG.debug("Could not find a proper no-arg constructor for the class ${clazz.simpleName}.") }
54-
else clazz.objectInstance as? T
55-
// We're doomed at this point, now I am become death, the destroyer of worlds
56-
?: null.also {
57-
LOG.debug(
58-
"No instance of type ${T::class.java.simpleName} could be found on the class ${clazz.simpleName}." +
59-
" Ensure that the class has an INSTANCE field or a no-arg constructor."
60-
)
61-
}
62-
}
63-
64-
/**
65-
* Finds all subtypes of a specified class
32+
* The function caches the results based on the configuration provided via the [block] lambda to avoid redundant
33+
* reflection calls.
6634
*
67-
* @param T The type for which to find subtypes.
68-
* @param config A pre-configured [ConfigurationBuilder].
69-
* @return A [Set] of [Class] objects representing all subtypes of the specified type.
35+
* @param T The type of instances to retrieve.
36+
* @param block A configuration lambda to customize the [ConfigurationBuilder] used to configure Reflections.
37+
*
38+
* @return A list of instances of type `T`
7039
*/
71-
inline fun <reified T : Any> getSubTypesOf(config: ConfigurationBuilder): Set<Class<*>> =
72-
Reflections(config).getSubTypesOf(T::class.java)
40+
inline fun <reified T : Any> getInstances(block: ConfigurationBuilder.() -> Unit = { forPackage("com.lambda") }): List<T> {
41+
val config = ConfigurationBuilder().apply(block)
42+
val cacheKey = Objects.hash(config.classLoaders, config.urls, config.scanners, config.inputsFilter)
7343

44+
// Use previously scanned classes or create a new reflections
45+
val reflections = cache.getOrPut(cacheKey) { Reflections(config) }
7446

75-
/**
76-
* Retrieves resources matching a specified pattern
77-
*
78-
* @param pattern The pattern to match resources against.
79-
* @param config A pre-configured [ConfigurationBuilder].
80-
* @return A [Set] of [String] representing resources matching the specified pattern.
81-
*/
82-
fun getResources(pattern: String, config: ConfigurationBuilder): Set<String> =
83-
Reflections(config).getResources(pattern)
47+
return reflections.getSubTypesOf(T::class.java)
48+
.mapNotNull { clazz -> createInstance<T>(clazz) }
49+
}
8450

8551
/**
86-
* Retrieves resources matching a specified [Pattern]
52+
* Retrieves all resource paths that match the given pattern.
53+
*
54+
* The function caches the results based on the configuration provided via the [block] lambda to avoid redundant
55+
* reflection calls.
56+
*
57+
* @param pattern The resource pattern to search for.
58+
* @param block A configuration lambda to customize the [ConfigurationBuilder] used to configure Reflections.
8759
*
88-
* @param pattern The [Pattern] to match resources against.
89-
* @param block A DSL block used to configure the [ReflectionConfigDsl].
90-
* @return A [Set] of [String] representing resources matching the specified pattern.
60+
* @return A set of resource paths that match the specified pattern.
9161
*/
92-
inline fun getResources(pattern: Pattern, block: ReflectionConfigDsl.() -> Unit): Set<String> =
93-
getResources(pattern.pattern(), config = getConfiguration(block))
62+
inline fun getResources(pattern: String, block: ConfigurationBuilder.() -> Unit = { forPackage("com.lambda") }): Set<String> {
63+
val config = ConfigurationBuilder().apply(block)
64+
val cacheKey = Objects.hash(config.classLoaders, config.urls, config.scanners, config.inputsFilter)
65+
66+
// Use previously scanned classes or create a new reflections
67+
val reflections = cache.getOrPut(cacheKey) { Reflections(config) }
68+
69+
return reflections.getResources(pattern)
70+
}
71+
72+
inline fun <reified T : Any> createInstance(clazz: Class<*>): T? {
73+
return when {
74+
clazz.isInterface || clazz.isEnum || clazz.isAnnotation || clazz.isObject -> {
75+
// Handle objects (singletons) or invalid types
76+
clazz.objectInstance as? T
77+
}
78+
else -> {
79+
// Look for a constructor with no parameters
80+
clazz.constructors
81+
.filterNot { Modifier.isAbstract(it.declaringClass.modifiers) } // Avoid abstract constructors
82+
.firstOrNull { it.parameterCount == 0 }?.newInstance() as? T
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)