All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zsqw123.catreflect.util.MethodUtil.kt Maven / Gradle / Ivy

package com.zsqw123.catreflect.util

import java.lang.reflect.Method
import java.util.*

private val methodCache: MutableMap = WeakHashMap()

internal class MethodDescriptor(
    var clazz: Class<*>,
    var methodName: String,
    var parameterType: Array>,
) {
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false

        other as MethodDescriptor

        if (clazz != other.clazz) return false
        if (methodName != other.methodName) return false
        if (!parameterType.contentEquals(other.parameterType)) return false

        return true
    }

    override fun hashCode(): Int {
        var result = clazz.hashCode()
        result = 31 * result + methodName.hashCode()
        result = 31 * result + parameterType.contentHashCode()
        return result
    }
}

internal fun methodMatch(
    clazz: Class<*>,
    methodName: String,
    parameterType: Array>,
    safe: Boolean = false,
): Method {
    // fast cache
    val md = MethodDescriptor(clazz, methodName, parameterType)
    val cache = methodCache[md]
    if (cache != null) return cache

    // fast match use Method
    try {
        val method = clazz.getMethod(methodName, *parameterType)
        method.isAccessible = true
        methodCache[md] = method
        return method
    } catch (_: NoSuchMethodException) {  /* SWALLOW */
    }

    // fast match use DeclaredMethod
    if (!safe) try {
        val method = clazz.getDeclaredMethod(methodName, *parameterType)
        method.isAccessible = true
        methodCache[md] = method
        return method
    } catch (_: NoSuchMethodException) {  /* SWALLOW */
    }

    // search all methods
    var allMethods = clazz.methods
    if (!safe) allMethods += clazz.declaredMethods
    val parameterCount = parameterType.size
    var bestRes: Method? = null
    var bestCost = Int.MAX_VALUE
    for (method in allMethods) {
        if (method.name != md.methodName) continue
        val types = method.parameterTypes
        if (types.size != parameterCount) continue
        var cost = 0
        var failed = false
        for (i in types.indices) {
            if (types[i] == parameterType[i]) continue
            if (types[i].canReplaceTo(parameterType[i])) {
                cost += 1
                continue
            }
            failed = true
            break
        }
        if (failed) continue
        if (cost < bestCost) {
            bestRes = method
            bestCost = cost
        }
    }
    if (bestRes != null) {
        bestRes.isAccessible = true
        methodCache[md] = bestRes
        return bestRes
    }
    throw NoSuchMethodException("$clazz#$methodName ${parameterType.toList()}")
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy