
dorkbox.classUtil.ReflectionUtils.kt Maven / Gradle / Ivy
/*
* Copyright 2023 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.classUtil
import dorkbox.collections.IdentityMap
import java.lang.reflect.AnnotatedElement
import java.lang.reflect.Method
/**
* @author bennidi
* Date: 2/16/12
* Time: 12:14 PM
* @author dorkbox
* Date: 2/2/15
*/
object ReflectionUtils {
/**
* Gets the version number.
*/
const val version = ClassHelper.version
@Suppress("UNCHECKED_CAST")
private val EMPTY_METHODS = arrayOfNulls(0) as Array
/**
* Get methods annotated with the specified annotation.
*
* @param target the class that you are looking for the methods on
* @param annotationClass the annotations that define the method you are looking for
* @param the annotation type
*
* @return the array of methods that match the target + annotation
*/
fun getMethods(target: Class<*>, annotationClass: Class): Array {
val methods = ArrayList()
getMethods(target, annotationClass, methods)
return methods.toArray(EMPTY_METHODS)
}
private fun getMethods(target: Class<*>, annotationClass: Class, methods: ArrayList) {
try {
for (method in target.getDeclaredMethods()) {
if (getAnnotation(method, annotationClass) != null) {
methods.add(method)
}
}
}
catch (ignored: Exception) {
}
// recursively go until root
if (target != Any::class.java) {
getMethods(target.superclass, annotationClass, methods)
}
}
/**
* Traverses the class hierarchy upwards, starting at the given subclass, looking
* for an override of the given methods -> finds the bottom most override of the given
* method if any exists
*/
fun getOverridingMethod(overridingMethod: Method, subclass: Class<*>): Method? {
var current = subclass
while (current != overridingMethod.declaringClass) {
current = try {
return current.getDeclaredMethod(overridingMethod.name, *overridingMethod.parameterTypes)
}
catch (e: NoSuchMethodException) {
current.superclass
}
}
return null
}
fun containsOverridingMethod(allMethods: Array, methodToCheck: Method): Boolean {
val length = allMethods.size
var method: Method
for (i in 0 until length) {
method = allMethods[i]
if (isOverriddenBy(methodToCheck, method)) {
return true
}
}
return false
}
/**
* Searches for an Annotation of the given type on the class. Supports meta annotations.
*
* @param from AnnotatedElement (class, method...)
* @param annotationType Annotation class to look for.
* @param Class of annotation type
*
* @return Annotation instance or null
*/
private fun getAnnotation(
from: AnnotatedElement,
annotationType: Class,
visited: IdentityMap
): A? {
if (visited.containsKey(from)) {
return null
}
visited[from] = java.lang.Boolean.TRUE
var ann: A? = from.getAnnotation(annotationType)
if (ann != null) {
return ann
}
for (metaAnn in from.annotations) {
ann = getAnnotation(metaAnn.annotationClass.java, annotationType, visited)
if (ann != null) {
return ann
}
}
return null
}
fun getAnnotation(from: AnnotatedElement, annotationType: Class): A? {
return getAnnotation(from, annotationType, IdentityMap())
}
private fun isOverriddenBy(superclassMethod: Method, subclassMethod: Method): Boolean {
// if the declaring classes are the same or the subclass method is not defined in the subclass
// hierarchy of the given superclass method or the method names are not the same then
// subclassMethod does not override superclassMethod
if (superclassMethod.declaringClass == subclassMethod.declaringClass ||
!superclassMethod.declaringClass.isAssignableFrom(subclassMethod.declaringClass) ||
superclassMethod.name != subclassMethod.name
) {
return false
}
val superClassMethodParameters = superclassMethod.parameterTypes
val subClassMethodParameters = subclassMethod.parameterTypes
// method must specify the same number of parameters
//the parameters must occur in the exact same order
for (i in subClassMethodParameters.indices) {
if (superClassMethodParameters[i] != subClassMethodParameters[i]) {
return false
}
}
return true
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy