dev.bpmcrafters.processengine.worker.registrar.ReflectionUtils.kt Maven / Gradle / Ivy
package dev.bpmcrafters.processengine.worker.registrar
import dev.bpmcrafters.processengine.worker.ProcessEngineWorker
import dev.bpmcrafters.processengine.worker.ProcessEngineWorker.Companion.DEFAULT_UNSET_TOPIC
import dev.bpmcrafters.processengine.worker.Variable
import dev.bpmcrafters.processengineapi.task.ServiceTaskCompletionApi
import dev.bpmcrafters.processengineapi.task.TaskInformation
import org.springframework.aop.support.AopUtils
import java.lang.reflect.Method
import java.lang.reflect.Parameter
import java.lang.reflect.ParameterizedType
import java.lang.reflect.WildcardType
import java.util.*
/**
* Checks if the method parameter is payload of type Map or compatible.
*/
fun Parameter.isPayload() = Map::class.java.isAssignableFrom(this.type)
&& (this.parameterizedType as ParameterizedType).isMapOfStringObject()
/**
* Checks if the parameter is task information.
*/
fun Parameter.isTaskInformation() = TaskInformation::class.java.isAssignableFrom(this.type)
/**
* Checks if the parameter is variable converter.
*/
fun Parameter.isVariableConverter() = VariableConverter::class.java.isAssignableFrom(this.type)
/**
* Checks if parameter is ExternalTaskCompletionApi
*/
fun Parameter.isTaskCompletionApiParameter() = ServiceTaskCompletionApi::class.java.isAssignableFrom(this.type)
/**
* Checks if the parameter is annotated with a Variable annotation.
*/
fun Parameter.isVariable() = this.isAnnotationPresent(Variable::class.java)
/**
* Extracts variable name from the variable annotation of the parameter.
*/
fun Parameter.extractVariableName() = this.getAnnotation(Variable::class.java).name
/**
* Extracts variable mandatory flag.
*/
fun Parameter.extractVariableMandatoryFlag() = this.getAnnotation(Variable::class.java).mandatory
/**
* Checks if parameter is an Optional
*/
fun Parameter.isOptional() = Optional::class.java.isAssignableFrom(this.type)
/**
* Extract variable names from all parameters.
*/
fun List.extractVariableNames(): Set = this.map { it.extractVariableName() }.toSet()
/**
* Checks if the method has a return type compatible with payload of type Map
*/
fun Method.hasPayloadReturnType() = Map::class.java.isAssignableFrom(this.returnType) // try if the type is compatible to Map
&& if (this.genericReturnType is ParameterizedType) {
// e.g. Map
(this.genericReturnType as ParameterizedType).isMapOfStringObject()
} else {
// e.g. class VariableMap implements Map (one of the interfaces are parameterized type matching the Map)
(this.genericReturnType as Class<*>).genericInterfaces.filterIsInstance().any { it.isMapOfStringObject() }
}
/*
* Checks a two-types parameter type for the type bounds.
* Verifies TYPE<*, *> to be compatible to TYPE.
*/
private fun ParameterizedType.isMapOfStringObject() = this.actualTypeArguments.let {
it.size == 2
&& it[0].typeName == "java.lang.String"
&& (it[1].typeName == "java.lang.Object"
|| (it[1] is WildcardType
&& (it[1] as WildcardType).upperBounds.size == 1
&& (it[1] as WildcardType).upperBounds[0].typeName == "java.lang.Object")
)
}
/**
* Checks if the return type is void.
*/
fun Method.hasVoidReturnType() = Void.TYPE == this.returnType
/**
* Retrieves list of worker methods.
*/
fun Any.getAnnotatedWorkers(): List = AopUtils
.getTargetClass(this)
.methods
.filter { m -> m.isAnnotationPresent(ProcessEngineWorker::class.java) }
/**
* Detects worker topic either using the annotation or defaulting to method name.
*/
fun Method.getTopic(): String {
val workerAnnotation = this.getAnnotation(ProcessEngineWorker::class.java)
return if (workerAnnotation.topic != DEFAULT_UNSET_TOPIC) {
workerAnnotation.topic
} else {
this.name
}
}
/**
* Returns the auto-completion flag from annotation.
*/
fun Method.getAutoComplete(): Boolean {
return this.getAnnotation(ProcessEngineWorker::class.java).autoComplete
}