** Methods for finding fields, methods and ctors that match given parameter types.
class ReflectUtils {
** Finds a field.
static Field? findField(Type type, Str fieldName, Type fieldType) {
// 'fields()' returns inherited slots, 'field(name)' does not
return type.fields.find |field| {
if (field.name != fieldName)
return false
return fits(field.type, fieldType)
}
}
** Finds a named ctor with the given parameter types.
static Method? findCtor(Type type, Str ctorName, Type[] params := [,]) {
// 'methods()' returns inherited slots, 'method(name)' does not
return type.methods.find |method| {
if (!method.isCtor)
return false
if (method.name != ctorName)
return false
return (paramTypesFitMethodSignature(params, method))
}
}
** Finds a named method with the given parameter types.
static Method? findMethod(Type type, Str name, Type[] params := [,], Bool isStatic := false, Type? returnType := null) {
// 'methods()' returns inherited slots, 'method(name)' does not
return type.methods.find |method| {
if (method.isCtor)
return false
if (method.name != name)
return false
if (method.isStatic != isStatic)
return false
if (returnType != null && !fits(method.returns, returnType))
return false
return (paramTypesFitMethodSignature(params, method))
}
}
** Returns 'true' if the given parameter types fit the method signature.
static Bool paramTypesFitMethodSignature(Type?[] params, Method? method) {
return method.params.all |methodParam, i->Bool| {
if (i >= params.size)
return methodParam.hasDefault
if (params[i] == null)
return methodParam.type.isNullable
return fits(params[i], methodParam.type)
}
}
** A replacement for 'Type.fits()' that takes into account type inference for Lists and Maps.
**
** Returns 'true' if 'typeA' *fits into* 'typeB'.
static Bool fits(Type? typeA, Type? typeB) {
if (typeA == typeB) return true
if (typeA == null || typeB == null) return false
if (typeA.name == "List" && typeB.name == "List")
return paramFits(typeA, typeB, "V")
if (typeA.name == "Map" && typeB.name == "Map")
return paramFits(typeA, typeB, "K") && paramFits(typeA, typeB, "V")
return typeA.fits(typeB)
}
private static Bool paramFits(Type? typeA, Type? typeB, Str key) {
paramTypeA := typeA.params[key] ?: Obj?#
paramTypeB := typeB.params[key] ?: Obj?#
return (paramTypeA.fits(paramTypeB) || paramTypeB.fits(paramTypeA))
}
}