Initial commit

This commit is contained in:
2025-06-25 19:05:35 +08:00
commit e949662e7c
104 changed files with 11697 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
plugins {
autowire(libs.plugins.kotlin.jvm)
autowire(libs.plugins.kotlin.dokka)
autowire(libs.plugins.maven.publish)
}
group = property.project.groupName
version = property.project.kavaref.core.version
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
withSourcesJar()
}
kotlin {
jvmToolchain(17)
sourceSets.all { languageSettings { languageVersion = "2.0" } }
compilerOptions {
freeCompilerArgs = listOf(
"-Xno-param-assertions",
"-Xno-call-assertions",
"-Xno-receiver-assertions"
)
}
}
dependencies {
// Android Only
compileOnly(projects.kavarefAndroidStub)
implementation(projects.kavarefExtension)
implementation(org.slf4j.slf4j.api)
implementation(org.slf4j.slf4j.simple)
}

View File

@@ -0,0 +1,433 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("unused", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST", "UnusedReceiverParameter", "DeprecatedCallableAddReplaceWith")
package com.highcapable.kavaref
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.condition.ConstructorCondition
import com.highcapable.kavaref.condition.FieldCondition
import com.highcapable.kavaref.condition.MethodCondition
import com.highcapable.kavaref.condition.base.MemberCondition
import com.highcapable.kavaref.condition.base.MemberCondition.Configuration.Companion.createConfiguration
import com.highcapable.kavaref.resolver.ConstructorResolver
import com.highcapable.kavaref.resolver.FieldResolver
import com.highcapable.kavaref.resolver.MethodResolver
import com.highcapable.kavaref.resolver.base.MemberResolver
import com.highcapable.kavaref.resolver.processor.MemberProcessor
import com.highcapable.kavaref.runtime.KavaRefRuntime
import com.highcapable.kavaref.runtime.KavaRefRuntime.Logger
import kotlin.reflect.KClass
/**
* This is the class created and managed by KavaRef.
*
* Try to use [KavaRef.resolve] to start a new reflection.
*/
class KavaRef private constructor() {
companion object {
/** Get or set the log level for KavaRef. */
@JvmStatic
var logLevel by KavaRefRuntime::logLevel
/**
* Set the logger for KavaRef.
* @param logger the logger to be set.
*/
@JvmStatic
fun setLogger(logger: Logger) = KavaRefRuntime.setLogger(logger)
/**
* Create a [MemberScope] instance to start a new reflection.
* @receiver the [KClass.java] to be reflected.
* @return [MemberScope]
*/
@JvmSynthetic
fun <T : Any> KClass<T>.resolve() = MemberScope(java.createConfiguration())
/**
* Create a [MemberScope] with a block to start a new reflection.
* @receiver the [KClass.java] to be reflected.
* @param block the block to configure the [MemberScope].
* @return [MemberScope]
*/
inline fun <T : Any> KClass<T>.resolve(block: MemberScope<T>.() -> Unit) = resolve().apply(block)
/**
* Create a [MemberScope] instance to start a new reflection.
* @receiver the [Class] to be reflected.
* @return [MemberScope]
*/
@JvmStatic
@JvmName("resolveClass")
fun <T : Any> Class<T>.resolve() = MemberScope(createConfiguration())
/**
* Create a [MemberScope] instance to start a new reflection.
* @see KClass.resolve
* @see Class.resolve
* @return [MemberScope]
*/
@JvmStatic
@JvmName("resolveObject")
fun <T : Any> T.resolve() = when (this) {
is KClass<*> -> MemberScope((this as KClass<T>).java.createConfiguration(memberInstance = this))
is Class<*> -> MemberScope((this as Class<T>).createConfiguration(memberInstance = this))
else -> MemberScope(javaClass.createConfiguration(memberInstance = this))
}
// Below are deprecated functions to prevent recursive calls.
private const val RECURSIVELY_CALL_DEPRECATED_MESSAGE = "You are calling resolve() recursively, it's an error and should delete it."
private const val RECURSIVELY_CALL_EXCEPTION_MESSAGE = "Not allowed to call resolve() recursively, please delete it."
/**
* This is a fake function call chains to avoid recursive calls to themselves.
*/
@Deprecated(message = RECURSIVELY_CALL_DEPRECATED_MESSAGE, level = DeprecationLevel.ERROR)
@JvmSynthetic
fun MemberScope<*>.resolve(): MemberScope<*> = error(RECURSIVELY_CALL_EXCEPTION_MESSAGE)
/**
* This is a fake function call chains to avoid recursive calls to themselves.
*/
@Deprecated(message = RECURSIVELY_CALL_DEPRECATED_MESSAGE, level = DeprecationLevel.ERROR)
@JvmSynthetic
fun MemberCondition<*, *, *>.resolve(): MemberCondition<*, *, *> = error(RECURSIVELY_CALL_EXCEPTION_MESSAGE)
/**
* This is a fake function call chains to avoid recursive calls to themselves.
*/
@Deprecated(message = RECURSIVELY_CALL_DEPRECATED_MESSAGE, level = DeprecationLevel.ERROR)
@JvmSynthetic
fun MemberResolver<*, *>.resolve(): MemberResolver<*, *> = error(RECURSIVELY_CALL_EXCEPTION_MESSAGE)
/**
* This is a fake function call chains to avoid recursive calls to themselves.
*/
@Deprecated(message = RECURSIVELY_CALL_DEPRECATED_MESSAGE, level = DeprecationLevel.ERROR)
@JvmSynthetic
fun List<MemberResolver<*, *>>.resolve(): List<MemberResolver<*, *>> = error(RECURSIVELY_CALL_EXCEPTION_MESSAGE)
}
/**
* The KavaRef scope for member reflection.
*
* [T] to specify the declaring class type of the member.
* @param configuration the configuration to be reflected.
*/
class MemberScope<T : Any> internal constructor(private val configuration: MemberCondition.Configuration<T>) {
/**
* Set the [MemberProcessor.Resolver] to be used for this reflection.
* @see MemberCondition.Configuration.processorResolver
* @see MemberProcessor.Resolver
* @param resolver the resolver to be used.
*/
fun processor(resolver: MemberProcessor.Resolver) = apply {
configuration.processorResolver = resolver
}
/**
* Enable optional mode.
* @see MemberCondition.Configuration.optional
* @param silent see [MemberCondition.Configuration.Optional.SILENT]
*/
fun optional(silent: Boolean = false) = apply {
configuration.optional = if (silent)
MemberCondition.Configuration.Optional.SILENT
else MemberCondition.Configuration.Optional.NOTICE
}
/**
* Start a new method reflection.
* @return [MethodCondition]
*/
fun method() = MethodCondition<T>().also {
it.configuration = configuration
}
/**
* Start a new method reflection.
* @see firstMethod
* @see firstMethodOrNull
* @param condition the condition.
* @return [MethodResolver]
*/
fun method(condition: MethodCondition<T>) = condition.build(configuration)
/**
* Start a new method reflection and return the first matching method.
* @see method
* @param condition the condition body.
* @return [MethodResolver]
*/
fun firstMethod(condition: MethodCondition<T>) = method(condition).first()
/**
* Start a new method reflection and return the first matching method or null.
* @see method
* @param condition the condition body.
* @return [MethodResolver] or null.
*/
fun firstMethodOrNull(condition: MethodCondition<T>) = method(condition).firstOrNull()
/**
* Start a new method reflection and return the last matching method.
* @see method
* @param condition the condition body.
* @return [MethodResolver]
*/
fun lastMethod(condition: MethodCondition<T>) = method(condition).last()
/**
* Start a new method reflection and return the last matching method or null.
* @see method
* @param condition the condition body.
* @return [MethodResolver] or null.
*/
fun lastMethodOrNull(condition: MethodCondition<T>) = method(condition).lastOrNull()
/**
* Start a new method reflection.
* @see firstMethod
* @see firstMethodOrNull
* @param condition the condition body.
* @return [MethodResolver]
*/
inline fun method(condition: MethodCondition<T>.() -> Unit) = method().apply(condition).build()
/**
* Start a new method reflection and return the first matching method.
* @see method
* @param condition the condition body.
* @return [MethodResolver]
*/
inline fun firstMethod(condition: MethodCondition<T>.() -> Unit = {}) = method(condition).first()
/**
* Start a new method reflection and return the first matching method or null.
* @see method
* @param condition the condition body.
* @return [MethodResolver] or null.
*/
inline fun firstMethodOrNull(condition: MethodCondition<T>.() -> Unit = {}) = method(condition).firstOrNull()
/**
* Start a new method reflection and return the last matching method.
* @see method
* @param condition the condition body.
* @return [MethodResolver]
*/
inline fun lastMethod(condition: MethodCondition<T>.() -> Unit = {}) = method(condition).last()
/**
* Start a new method reflection and return the last matching method or null.
* @see method
* @param condition the condition body.
* @return [MethodResolver] or null.
*/
inline fun lastMethodOrNull(condition: MethodCondition<T>.() -> Unit = {}) = method(condition).lastOrNull()
/**
* Start a new constructor reflection.
* @return [ConstructorCondition]
*/
fun constructor() = ConstructorCondition<T>().also {
it.configuration = configuration
}
/**
* Start a new constructor reflection.
* @see firstConstructor
* @see firstConstructorOrNull
* @param condition the condition.
* @return [ConstructorResolver]
*/
fun constructor(condition: ConstructorCondition<T>) = condition.build(configuration)
/**
* Start a new constructor reflection and return the first matching constructor.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver]
*/
fun firstConstructor(condition: ConstructorCondition<T>) = constructor(condition).first()
/**
* Start a new constructor reflection and return the first matching constructor or null.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver] or null.
*/
fun firstConstructorOrNull(condition: ConstructorCondition<T>) = constructor(condition).firstOrNull()
/**
* Start a new constructor reflection and return the last matching constructor.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver]
*/
fun lastConstructor(condition: ConstructorCondition<T>) = constructor(condition).last()
/**
* Start a new constructor reflection and return the last matching constructor or null.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver] or null.
*/
fun lastConstructorOrNull(condition: ConstructorCondition<T>) = constructor(condition).lastOrNull()
/**
* Start a new constructor reflection.
* @see firstConstructor
* @see firstConstructorOrNull
* @param condition the condition body.
* @return [ConstructorResolver]
*/
inline fun constructor(condition: ConstructorCondition<T>.() -> Unit) = constructor().apply(condition).build()
/**
* Start a new constructor reflection and return the first matching constructor.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver]
*/
inline fun firstConstructor(condition: ConstructorCondition<T>.() -> Unit = {}) = constructor(condition).first()
/**
* Start a new constructor reflection and return the first matching constructor or null.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver] or null.
*/
inline fun firstConstructorOrNull(condition: ConstructorCondition<T>.() -> Unit = {}) = constructor(condition).firstOrNull()
/**
* Start a new constructor reflection and return the last matching constructor.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver]
*/
inline fun lastConstructor(condition: ConstructorCondition<T>.() -> Unit = {}) = constructor(condition).last()
/**
* Start a new constructor reflection and return the last matching constructor or null.
* @see constructor
* @param condition the condition body.
* @return [ConstructorResolver] or null.
*/
inline fun lastConstructorOrNull(condition: ConstructorCondition<T>.() -> Unit = {}) = constructor(condition).lastOrNull()
/**
* Start a new field reflection.
* @return [FieldCondition]
*/
fun field() = FieldCondition<T>().also {
it.configuration = configuration
}
/**
* Start a new field reflection.
* @see firstField
* @see firstFieldOrNull
* @param condition the condition.
* @return [FieldResolver]
*/
fun field(condition: FieldCondition<T>) = condition.build(configuration)
/**
* Start a new field reflection and return the first matching field.
* @see field
* @param condition the condition body.
* @return [FieldResolver]
*/
fun firstField(condition: FieldCondition<T>) = field(condition).first()
/**
* Start a new field reflection and return the first matching field or null.
* @see field
* @param condition the condition body.
* @return [FieldResolver] or null.
*/
fun firstFieldOrNull(condition: FieldCondition<T>) = field(condition).firstOrNull()
/**
* Start a new field reflection and return the last matching field.
* @see field
* @param condition the condition body.
* @return [FieldResolver]
*/
fun lastField(condition: FieldCondition<T>) = field(condition).last()
/**
* Start a new field reflection and return the last matching field or null.
* @see field
* @param condition the condition body.
* @return [FieldResolver] or null.
*/
fun lastFieldOrNull(condition: FieldCondition<T>) = field(condition).lastOrNull()
/**
* Start a new field reflection.
* @see firstField
* @see firstFieldOrNull
* @param condition the condition body.
* @return [FieldResolver]
*/
inline fun field(condition: FieldCondition<T>.() -> Unit) = field().apply(condition).build()
/**
* Start a new field reflection and return the first matching field.
* @see field
* @param condition the condition body.
* @return [FieldResolver]
*/
inline fun firstField(condition: FieldCondition<T>.() -> Unit = {}) = field(condition).first()
/**
* Start a new field reflection and return the first matching field or null.
* @see field
* @param condition the condition body.
* @return [FieldResolver] or null.
*/
inline fun firstFieldOrNull(condition: FieldCondition<T>.() -> Unit = {}) = field(condition).firstOrNull()
/**
* Start a new field reflection and return the last matching field.
* @see field
* @param condition the condition body.
* @return [FieldResolver]
*/
inline fun lastField(condition: FieldCondition<T>.() -> Unit = {}) = field(condition).last()
/**
* Start a new field reflection and return the last matching field or null.
* @see field
* @param condition the condition body.
* @return [FieldResolver] or null.
*/
inline fun lastFieldOrNull(condition: FieldCondition<T>.() -> Unit = {}) = field(condition).lastOrNull()
}
}

View File

@@ -0,0 +1,87 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
package com.highcapable.kavaref.condition
import com.highcapable.kavaref.condition.base.ExecutableCondition
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.kavaref.resolver.ConstructorResolver
import com.highcapable.kavaref.resolver.processor.MemberProcessor
import java.lang.reflect.Constructor
/**
* Condition for [Constructor] of [ConstructorResolver].
*/
class ConstructorCondition<T : Any> : ExecutableCondition<Constructor<T>, ConstructorResolver<T>, T>() {
override fun name(name: String) = apply { super.name(name) }
override fun name(condition: (String) -> Boolean) = apply { super.name(condition) }
override fun modifiers(vararg modifiers: Modifiers) = apply { super.modifiers(*modifiers) }
override fun modifiersNot(vararg modifiers: Modifiers) = apply { super.modifiersNot(*modifiers) }
override fun modifiers(condition: (Set<Modifiers>) -> Boolean) = apply { super.modifiers(condition) }
override fun isSynthetic(isSynthetic: Boolean) = apply { super.isSynthetic(isSynthetic) }
override fun isSyntheticNot(isSynthetic: Boolean) = apply { super.isSyntheticNot(isSynthetic) }
override fun annotations(vararg annotations: Any) = apply { super.annotations(*annotations) }
override fun annotationsNot(vararg annotations: Any) = apply { super.annotationsNot(*annotations) }
override fun genericString(genericString: String) = apply { super.genericString(genericString) }
override fun parameters(vararg types: Any) = apply { super.parameters(*types) }
override fun parametersNot(vararg types: Any) = apply { super.parametersNot(*types) }
override fun parameters(condition: (List<Class<*>>) -> Boolean) = apply { super.parameters(condition) }
override fun emptyParameters() = apply { super.emptyParameters() }
override fun emptyParametersNot() = apply { super.emptyParametersNot() }
override fun typeParameters(vararg types: TypeMatcher) = apply { super.typeParameters(*types) }
override fun typeParametersNot(vararg types: TypeMatcher) = apply { super.typeParametersNot(*types) }
override fun parameterCount(count: Int) = apply { super.parameterCount(count) }
override fun parameterCount(condition: (Int) -> Boolean) = apply { super.parameterCount(condition) }
override fun exceptionTypes(vararg types: Any) = apply { super.exceptionTypes(*types) }
override fun exceptionTypesNot(vararg types: Any) = apply { super.exceptionTypesNot(*types) }
override fun genericExceptionTypes(vararg types: TypeMatcher) = apply { super.genericExceptionTypes(*types) }
override fun genericExceptionTypesNot(vararg types: TypeMatcher) = apply { super.genericExceptionTypesNot(*types) }
override fun genericParameters(vararg types: TypeMatcher) = apply { super.genericParameters(*types) }
override fun genericParametersNot(vararg types: TypeMatcher) = apply { super.genericParametersNot(*types) }
override fun isVarArgs(isVarArgs: Boolean) = apply { super.isVarArgs(isVarArgs) }
override fun isVarArgsNot(isVarArgs: Boolean) = apply { super.isVarArgsNot(isVarArgs) }
override fun parameterAnnotations(vararg annotations: Set<Any>) = apply { super.parameterAnnotations(*annotations) }
override fun parameterAnnotationsNot(vararg annotations: Set<Any>) = apply { super.parameterAnnotationsNot(*annotations) }
override fun annotatedReturnType(vararg types: Any) = apply { super.annotatedReturnType(*types) }
override fun annotatedReturnTypeNot(vararg types: Any) = apply { super.annotatedReturnTypeNot(*types) }
override fun annotatedReceiverType(vararg types: Any) = apply { super.annotatedReceiverType(*types) }
override fun annotatedReceiverTypeNot(vararg types: Any) = apply { super.annotatedReceiverTypeNot(*types) }
override fun annotatedParameterTypes(vararg types: Any) = apply { super.annotatedParameterTypes(*types) }
override fun annotatedParameterTypesNot(vararg types: Any) = apply { super.annotatedParameterTypesNot(*types) }
override fun annotatedExceptionTypes(vararg types: Any) = apply { super.annotatedExceptionTypes(*types) }
override fun annotatedExceptionTypesNot(vararg types: Any) = apply { super.annotatedExceptionTypesNot(*types) }
override fun superclass() = apply { super.superclass() }
override fun copy() = ConstructorCondition<T>().also {
initializeCopiedData(it)
}
override fun build(configuration: Configuration<T>?): List<ConstructorResolver<T>> {
configuration?.let { checkAndSetConfiguration(it) }
return MemberProcessor.resolve(condition = this, this.configuration)
}
override val conditionStringMap get() = super.conditionStringMap
}

View File

@@ -0,0 +1,153 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("unused", "DuplicatedCode")
package com.highcapable.kavaref.condition
import com.highcapable.kavaref.condition.base.MemberCondition
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.kavaref.resolver.FieldResolver
import com.highcapable.kavaref.resolver.processor.MemberProcessor
import java.lang.reflect.Field
import java.lang.reflect.Type
/**
* Condition for [Field] of [FieldResolver].
*/
class FieldCondition<T : Any> : MemberCondition<Field, FieldResolver<T>, T>() {
/** @see Field.isEnumConstant */
var isEnumConstant: Boolean? = null
/** @see Field.isEnumConstant */
var isEnumConstantNot: Boolean? = null
/** @see Field.getType */
var type: Any? = null
/** @see Field.getType */
var typeCondition: ((Class<*>) -> Boolean)? = null
/** @see Field.getGenericType */
var genericType: TypeMatcher? = null
/** @see Field.getGenericType */
var genericTypeCondition: ((Type) -> Boolean)? = null
override fun name(name: String) = apply { super.name(name) }
override fun name(condition: (String) -> Boolean) = apply { super.name(condition) }
override fun modifiers(vararg modifiers: Modifiers) = apply { super.modifiers(*modifiers) }
override fun modifiersNot(vararg modifiers: Modifiers) = apply { super.modifiersNot(*modifiers) }
override fun modifiers(condition: (Set<Modifiers>) -> Boolean) = apply { super.modifiers(condition) }
override fun isSynthetic(isSynthetic: Boolean) = apply { super.isSynthetic(isSynthetic) }
override fun isSyntheticNot(isSynthetic: Boolean) = apply { super.isSyntheticNot(isSynthetic) }
override fun annotations(vararg annotations: Any) = apply { super.annotations(*annotations) }
override fun annotationsNot(vararg annotations: Any) = apply { super.annotationsNot(*annotations) }
override fun genericString(genericString: String) = apply { super.genericString(genericString) }
override fun superclass() = apply { super.superclass() }
/** @see Field.isEnumConstant */
fun isEnumConstant(isEnumConstant: Boolean) = apply {
this.isEnumConstant = isEnumConstant
}
/** @see Field.isEnumConstant */
fun isEnumConstantNot(isEnumConstant: Boolean) = apply {
this.isEnumConstantNot = isEnumConstant
}
/** @see Field.getType */
fun type(type: Any) = apply {
this.type = type
}
/** @see Field.getType */
fun type(condition: (Class<*>) -> Boolean) = apply {
this.typeCondition = condition
}
/** @see Field.getGenericType */
fun genericType(type: TypeMatcher) = apply {
this.genericType = type
}
/** @see Field.getGenericType */
fun genericType(condition: (Type) -> Boolean) = apply {
this.genericTypeCondition = condition
}
override fun initializeCopiedData(newSelf: MemberCondition<Field, FieldResolver<T>, T>) {
super.initializeCopiedData(newSelf)
(newSelf as? FieldCondition)?.also {
it.isEnumConstant = isEnumConstant
it.isEnumConstantNot = isEnumConstantNot
it.type = type
it.typeCondition = typeCondition
it.genericType = genericType
it.genericTypeCondition = genericTypeCondition
}
}
override fun initializeMergedData(other: MemberCondition<Field, FieldResolver<T>, T>) {
super.initializeMergedData(other)
(other as? FieldCondition)?.also { condition ->
condition.isEnumConstant?.let { isEnumConstant = it }
condition.isEnumConstantNot?.let { isEnumConstantNot = it }
condition.type?.let { type = it }
condition.typeCondition?.let { typeCondition = it }
condition.genericType?.let { genericType = it }
condition.genericTypeCondition?.let { genericTypeCondition = it }
}
}
override fun copy() = FieldCondition<T>().also {
initializeCopiedData(it)
}
override fun build(configuration: Configuration<T>?): List<FieldResolver<T>> {
configuration?.let { checkAndSetConfiguration(it) }
return MemberProcessor.resolve(condition = this, this.configuration)
}
override val conditionStringMap
get() = super.conditionStringMap + mapOf(
IS_ENUM_CONSTANT to isEnumConstant,
IS_ENUM_CONSTANT_NOT to isEnumConstantNot,
TYPE to type,
TYPE_CONDITION to typeCondition,
GENERIC_TYPE to genericType,
GENERIC_TYPE_CONDITION to genericTypeCondition
)
companion object {
const val IS_ENUM_CONSTANT = "isEnumConstant"
const val IS_ENUM_CONSTANT_NOT = "isEnumConstantNot"
const val TYPE = "type"
const val TYPE_CONDITION = "typeCondition"
const val GENERIC_TYPE = "genericType"
const val GENERIC_TYPE_CONDITION = "genericTypeCondition"
}
}

View File

@@ -0,0 +1,181 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("unused", "DuplicatedCode")
package com.highcapable.kavaref.condition
import com.highcapable.kavaref.condition.base.ExecutableCondition
import com.highcapable.kavaref.condition.base.MemberCondition
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.kavaref.resolver.MethodResolver
import com.highcapable.kavaref.resolver.processor.MemberProcessor
import java.lang.reflect.Method
/**
* Condition for [Method] of [MethodResolver].
*/
class MethodCondition<T : Any> : ExecutableCondition<Method, MethodResolver<T>, T>() {
/** @see Method.getReturnType */
var returnType: Any? = null
/** @see Method.getReturnType */
var returnTypeCondition: ((Class<*>) -> Boolean)? = null
/** @see Method.isBridge */
var isBridge: Boolean? = null
/** @see Method.isBridge */
var isBridgeNot: Boolean? = null
/** @see Method.isDefault */
var isDefault: Boolean? = null
/** @see Method.isDefault */
var isDefaultNot: Boolean? = null
override fun name(name: String) = apply { super.name(name) }
override fun name(condition: (String) -> Boolean) = apply { super.name(condition) }
override fun modifiers(vararg modifiers: Modifiers) = apply { super.modifiers(*modifiers) }
override fun modifiersNot(vararg modifiers: Modifiers) = apply { super.modifiersNot(*modifiers) }
override fun modifiers(condition: (Set<Modifiers>) -> Boolean) = apply { super.modifiers(condition) }
override fun isSynthetic(isSynthetic: Boolean) = apply { super.isSynthetic(isSynthetic) }
override fun isSyntheticNot(isSynthetic: Boolean) = apply { super.isSyntheticNot(isSynthetic) }
override fun annotations(vararg annotations: Any) = apply { super.annotations(*annotations) }
override fun annotationsNot(vararg annotations: Any) = apply { super.annotationsNot(*annotations) }
override fun genericString(genericString: String) = apply { super.genericString(genericString) }
override fun parameters(vararg types: Any) = apply { super.parameters(*types) }
override fun parametersNot(vararg types: Any) = apply { super.parametersNot(*types) }
override fun parameters(condition: (List<Class<*>>) -> Boolean) = apply { super.parameters(condition) }
override fun emptyParameters() = apply { super.emptyParameters() }
override fun emptyParametersNot() = apply { super.emptyParametersNot() }
override fun typeParameters(vararg types: TypeMatcher) = apply { super.typeParameters(*types) }
override fun typeParametersNot(vararg types: TypeMatcher) = apply { super.typeParametersNot(*types) }
override fun parameterCount(count: Int) = apply { super.parameterCount(count) }
override fun parameterCount(condition: (Int) -> Boolean) = apply { super.parameterCount(condition) }
override fun exceptionTypes(vararg types: Any) = apply { super.exceptionTypes(*types) }
override fun exceptionTypesNot(vararg types: Any) = apply { super.exceptionTypesNot(*types) }
override fun genericExceptionTypes(vararg types: TypeMatcher) = apply { super.genericExceptionTypes(*types) }
override fun genericExceptionTypesNot(vararg types: TypeMatcher) = apply { super.genericExceptionTypesNot(*types) }
override fun genericParameters(vararg types: TypeMatcher) = apply { super.genericParameters(*types) }
override fun genericParametersNot(vararg types: TypeMatcher) = apply { super.genericParametersNot(*types) }
override fun isVarArgs(isVarArgs: Boolean) = apply { super.isVarArgs(isVarArgs) }
override fun isVarArgsNot(isVarArgs: Boolean) = apply { super.isVarArgsNot(isVarArgs) }
override fun parameterAnnotations(vararg annotations: Set<Any>) = apply { super.parameterAnnotations(*annotations) }
override fun parameterAnnotationsNot(vararg annotations: Set<Any>) = apply { super.parameterAnnotationsNot(*annotations) }
override fun annotatedReturnType(vararg types: Any) = apply { super.annotatedReturnType(*types) }
override fun annotatedReturnTypeNot(vararg types: Any) = apply { super.annotatedReturnTypeNot(*types) }
override fun annotatedReceiverType(vararg types: Any) = apply { super.annotatedReceiverType(*types) }
override fun annotatedReceiverTypeNot(vararg types: Any) = apply { super.annotatedReceiverTypeNot(*types) }
override fun annotatedParameterTypes(vararg types: Any) = apply { super.annotatedParameterTypes(*types) }
override fun annotatedParameterTypesNot(vararg types: Any) = apply { super.annotatedParameterTypesNot(*types) }
override fun annotatedExceptionTypes(vararg types: Any) = apply { super.annotatedExceptionTypes(*types) }
override fun annotatedExceptionTypesNot(vararg types: Any) = apply { super.annotatedExceptionTypesNot(*types) }
override fun superclass() = apply { super.superclass() }
/** @see Method.getReturnType */
fun returnType(type: Any) = apply {
this.returnType = type
}
/** @see Method.getReturnType */
fun returnType(condition: (Class<*>) -> Boolean) = apply {
this.returnTypeCondition = condition
}
/** @see Method.isBridge */
fun isBridge(isBridge: Boolean) = apply {
this.isBridge = isBridge
}
/** @see Method.isBridge */
fun isBridgeNot(isBridge: Boolean) = apply {
this.isBridgeNot = isBridge
}
/** @see Method.isDefault */
fun isDefault(isDefault: Boolean) = apply {
this.isDefault = isDefault
}
/** @see Method.isDefault */
fun isDefaultNot(isDefault: Boolean) = apply {
this.isDefaultNot = isDefault
}
override fun initializeCopiedData(newSelf: MemberCondition<Method, MethodResolver<T>, T>) {
super.initializeCopiedData(newSelf)
(newSelf as? MethodCondition)?.also {
it.returnType = returnType
it.returnTypeCondition = returnTypeCondition
it.isBridge = isBridge
it.isBridgeNot = isBridgeNot
it.isDefault = isDefault
it.isDefaultNot = isDefaultNot
}
}
override fun initializeMergedData(other: MemberCondition<Method, MethodResolver<T>, T>) {
super.initializeMergedData(other)
(other as? MethodCondition)?.also { condition ->
condition.returnType?.let { returnType = it }
condition.returnTypeCondition?.let { returnTypeCondition = it }
condition.isBridge?.let { isBridge = it }
condition.isBridgeNot?.let { isBridgeNot = it }
condition.isDefault?.let { isDefault = it }
condition.isDefaultNot?.let { isDefaultNot = it }
}
}
override fun copy() = MethodCondition<T>().also {
initializeCopiedData(it)
}
override fun build(configuration: Configuration<T>?): List<MethodResolver<T>> {
configuration?.let { checkAndSetConfiguration(it) }
return MemberProcessor.resolve(condition = this, this.configuration)
}
override val conditionStringMap
get() = super.conditionStringMap + mapOf(
RETURN_TYPE to returnType,
RETURN_TYPE_CONDITION to returnTypeCondition,
IS_BRIDGE to isBridge,
IS_BRIDGE_NOT to isBridgeNot,
IS_DEFAULT to isDefault,
IS_DEFAULT_NOT to isDefaultNot
)
companion object {
const val RETURN_TYPE = "returnType"
const val RETURN_TYPE_CONDITION = "returnTypeCondition"
const val IS_BRIDGE = "isBridge"
const val IS_BRIDGE_NOT = "isBridgeNot"
const val IS_DEFAULT = "isDefault"
const val IS_DEFAULT_NOT = "isDefaultNot"
}
}

View File

@@ -0,0 +1,433 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("DuplicatedCode")
package com.highcapable.kavaref.condition.base
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.resolver.base.MemberResolver
import java.lang.reflect.Executable
/**
* Base class for conditions that are applicable to executable members (methods and constructors) [E], [R].
*
* [T] to specify the declaring class type of the executable.
*/
abstract class ExecutableCondition<E : Executable, R : MemberResolver<E, T>, T : Any> : MemberCondition<E, R, T>() {
/** @see Executable.getParameterTypes */
val parameters = mutableListOf<Any>()
/** @see Executable.getParameterTypes */
val parametersNot = mutableListOf<Any>()
/** @see Executable.getParameterTypes */
var parametersCondition: ((List<Class<*>>) -> Boolean)? = null
/** @see Executable.getTypeParameters */
val typeParameters = mutableSetOf<TypeMatcher>()
/** @see Executable.getTypeParameters */
val typeParametersNot = mutableSetOf<TypeMatcher>()
/** @see Executable.getParameterCount */
var parameterCount: Int? = null
/** @see Executable.getParameterCount */
var parameterCountCondition: ((Int) -> Boolean)? = null
/** @see Executable.getExceptionTypes */
val exceptionTypes = mutableSetOf<Any>()
/** @see Executable.getExceptionTypes */
val exceptionTypesNot = mutableSetOf<Any>()
/** @see Executable.getGenericExceptionTypes */
val genericExceptionTypes = mutableSetOf<TypeMatcher>()
/** @see Executable.getGenericExceptionTypes */
val genericExceptionTypesNot = mutableSetOf<TypeMatcher>()
/** @see Executable.getGenericParameterTypes */
val genericParameters = mutableSetOf<TypeMatcher>()
/** @see Executable.getGenericParameterTypes */
val genericParametersNot = mutableSetOf<TypeMatcher>()
/** @see Executable.isVarArgs */
var isVarArgs: Boolean? = null
/** @see Executable.isVarArgs */
var isVarArgsNot: Boolean? = null
/** @see Executable.getParameterAnnotations */
val parameterAnnotations = mutableListOf<Set<Any>>()
/** @see Executable.getParameterAnnotations */
val parameterAnnotationsNot = mutableListOf<Set<Any>>()
/** @see Executable.getAnnotatedReturnType */
val annotatedReturnType = mutableSetOf<Any>()
/** @see Executable.getAnnotatedReturnType */
val annotatedReturnTypeNot = mutableSetOf<Any>()
/** @see Executable.getAnnotatedReceiverType */
val annotatedReceiverType = mutableSetOf<Any>()
/** @see Executable.getAnnotatedReceiverType */
val annotatedReceiverTypeNot = mutableSetOf<Any>()
/** @see Executable.getAnnotatedParameterTypes */
val annotatedParameterTypes = mutableSetOf<Any>()
/** @see Executable.getAnnotatedParameterTypes */
val annotatedParameterTypesNot = mutableSetOf<Any>()
/** @see Executable.getAnnotatedExceptionTypes */
val annotatedExceptionTypes = mutableSetOf<Any>()
/** @see Executable.getAnnotatedExceptionTypes */
val annotatedExceptionTypesNot = mutableSetOf<Any>()
/** @see Executable.getParameterTypes */
open fun parameters(vararg types: Any) = apply {
this.parameters.addAll(types)
}
/** @see Executable.getParameterTypes */
open fun parametersNot(vararg types: Any) = apply {
this.parametersNot.addAll(types)
}
/** @see Executable.getParameterTypes */
open fun parameters(condition: (List<Class<*>>) -> Boolean) = apply {
this.parametersCondition = condition
}
/**
* Set [parameterCount] to `0` to match methods with no parameters.
* @see Executable.getParameterCount
*/
open fun emptyParameters() = apply {
this.parameterCount = 0
}
/**
* Set [parameterCountCondition] to check if the method has parameters.
* @see Executable.getParameterCount
*/
open fun emptyParametersNot() = apply {
this.parameterCountCondition = { it > 0 }
}
/** @see Executable.getTypeParameters */
open fun typeParameters(vararg types: TypeMatcher) = apply {
this.typeParameters.addAll(types)
}
/** @see Executable.getTypeParameters */
open fun typeParametersNot(vararg types: TypeMatcher) = apply {
this.typeParametersNot.addAll(types)
}
/** @see Executable.getParameterCount */
open fun parameterCount(count: Int) = apply {
this.parameterCount = count
}
/** @see Executable.getParameterCount */
open fun parameterCount(condition: (Int) -> Boolean) = apply {
this.parameterCountCondition = condition
}
/** @see Executable.getExceptionTypes */
open fun exceptionTypes(vararg types: Any) = apply {
this.exceptionTypes.addAll(types)
}
/** @see Executable.getExceptionTypes */
open fun exceptionTypesNot(vararg types: Any) = apply {
this.exceptionTypesNot.addAll(types)
}
/** @see Executable.getGenericExceptionTypes */
open fun genericExceptionTypes(vararg types: TypeMatcher) = apply {
this.genericExceptionTypes.addAll(types)
}
/** @see Executable.getGenericExceptionTypes */
open fun genericExceptionTypesNot(vararg types: TypeMatcher) = apply {
this.genericExceptionTypesNot.addAll(types)
}
/** @see Executable.getGenericParameterTypes */
open fun genericParameters(vararg types: TypeMatcher) = apply {
this.genericParameters.addAll(types)
}
/** @see Executable.getGenericParameterTypes */
open fun genericParametersNot(vararg types: TypeMatcher) = apply {
this.genericParametersNot.addAll(types)
}
/** @see Executable.isVarArgs */
open fun isVarArgs(isVarArgs: Boolean) = apply {
this.isVarArgs = isVarArgs
}
/** @see Executable.isVarArgs */
open fun isVarArgsNot(isVarArgs: Boolean) = apply {
this.isVarArgsNot = isVarArgs
}
/** @see Executable.getParameterAnnotations */
open fun parameterAnnotations(vararg annotations: Set<Any>) = apply {
this.parameterAnnotations.addAll(annotations)
}
/** @see Executable.getParameterAnnotations */
open fun parameterAnnotationsNot(vararg annotations: Set<Any>) = apply {
this.parameterAnnotationsNot.addAll(annotations)
}
/** @see Executable.getAnnotatedReturnType */
open fun annotatedReturnType(vararg types: Any) = apply {
this.annotatedReturnType.addAll(types.toList())
}
/** @see Executable.getAnnotatedReturnType */
open fun annotatedReturnTypeNot(vararg types: Any) = apply {
this.annotatedReturnTypeNot.addAll(types.toList())
}
/** @see Executable.getAnnotatedReceiverType */
open fun annotatedReceiverType(vararg types: Any) = apply {
this.annotatedReceiverType.addAll(types.toList())
}
/** @see Executable.getAnnotatedReceiverType */
open fun annotatedReceiverTypeNot(vararg types: Any) = apply {
this.annotatedReceiverTypeNot.addAll(types.toList())
}
/** @see Executable.getAnnotatedParameterTypes */
open fun annotatedParameterTypes(vararg types: Any) = apply {
this.annotatedParameterTypes.addAll(types.toList())
}
/** @see Executable.getAnnotatedParameterTypes */
open fun annotatedParameterTypesNot(vararg types: Any) = apply {
this.annotatedParameterTypesNot.addAll(types.toList())
}
/** @see Executable.getAnnotatedExceptionTypes */
open fun annotatedExceptionTypes(vararg types: Any) = apply {
this.annotatedExceptionTypes.addAll(types.toList())
}
/** @see Executable.getAnnotatedExceptionTypes */
open fun annotatedExceptionTypesNot(vararg types: Any) = apply {
this.annotatedExceptionTypesNot.addAll(types.toList())
}
override fun initializeCopiedData(newSelf: MemberCondition<E, R, T>) {
super.initializeCopiedData(newSelf)
(newSelf as? ExecutableCondition<E, R, T>)?.also {
it.parameters.addAll(parameters)
it.parametersNot.addAll(parametersNot)
it.parametersCondition = parametersCondition
it.parameterCount = parameterCount
it.parameterCountCondition = parameterCountCondition
it.typeParameters.addAll(typeParameters)
it.typeParametersNot.addAll(typeParametersNot)
it.exceptionTypes.addAll(exceptionTypes)
it.exceptionTypesNot.addAll(exceptionTypesNot)
it.genericExceptionTypes.addAll(genericExceptionTypes)
it.genericExceptionTypesNot.addAll(genericExceptionTypesNot)
it.genericParameters.addAll(genericParameters)
it.genericParametersNot.addAll(genericParametersNot)
it.isVarArgs = isVarArgs
it.isVarArgsNot = isVarArgsNot
it.parameterAnnotations.addAll(parameterAnnotations)
it.parameterAnnotationsNot.addAll(parameterAnnotationsNot)
it.annotatedReturnType.addAll(annotatedReturnType)
it.annotatedReturnTypeNot.addAll(annotatedReturnTypeNot)
it.annotatedReceiverType.addAll(annotatedReceiverType)
it.annotatedReceiverTypeNot.addAll(annotatedReceiverTypeNot)
it.annotatedParameterTypes.addAll(annotatedParameterTypes)
it.annotatedParameterTypesNot.addAll(annotatedParameterTypesNot)
it.annotatedExceptionTypes.addAll(annotatedExceptionTypes)
it.annotatedExceptionTypesNot.addAll(annotatedExceptionTypesNot)
}
}
override fun initializeMergedData(other: MemberCondition<E, R, T>) {
super.initializeMergedData(other)
(other as? ExecutableCondition<E, R, T>)?.also { condition ->
condition.parameters.takeIf { it.isNotEmpty() }?.let {
parameters.clear()
parameters.addAll(it)
}
condition.parametersNot.takeIf { it.isNotEmpty() }?.let {
parametersNot.clear()
parametersNot.addAll(it)
}
condition.parametersCondition?.let { parametersCondition = it }
condition.parameterCount?.let { parameterCount = it }
condition.parameterCountCondition?.let { parameterCountCondition = it }
condition.typeParameters.takeIf { it.isNotEmpty() }?.let {
typeParameters.clear()
typeParameters.addAll(it)
}
condition.typeParametersNot.takeIf { it.isNotEmpty() }?.let {
typeParametersNot.clear()
typeParametersNot.addAll(it)
}
condition.exceptionTypes.takeIf { it.isNotEmpty() }?.let {
exceptionTypes.clear()
exceptionTypes.addAll(it)
}
condition.exceptionTypesNot.takeIf { it.isNotEmpty() }?.let {
exceptionTypesNot.clear()
exceptionTypesNot.addAll(it)
}
condition.genericExceptionTypes.takeIf { it.isNotEmpty() }?.let {
genericExceptionTypes.clear()
genericExceptionTypes.addAll(it)
}
condition.genericExceptionTypesNot.takeIf { it.isNotEmpty() }?.let {
genericExceptionTypesNot.clear()
genericExceptionTypesNot.addAll(it)
}
condition.genericParameters.takeIf { it.isNotEmpty() }?.let {
genericParameters.clear()
genericParameters.addAll(it)
}
condition.genericParametersNot.takeIf { it.isNotEmpty() }?.let {
genericParametersNot.clear()
genericParametersNot.addAll(it)
}
condition.isVarArgs?.let { isVarArgs = it }
condition.isVarArgsNot?.let { isVarArgsNot = it }
condition.parameterAnnotations.takeIf { it.isNotEmpty() }?.let {
parameterAnnotations.clear()
parameterAnnotations.addAll(it)
}
condition.parameterAnnotationsNot.takeIf { it.isNotEmpty() }?.let {
parameterAnnotationsNot.clear()
parameterAnnotationsNot.addAll(it)
}
condition.annotatedReturnType.takeIf { it.isNotEmpty() }?.let {
annotatedReturnType.clear()
annotatedReturnType.addAll(it)
}
condition.annotatedReturnTypeNot.takeIf { it.isNotEmpty() }?.let {
annotatedReturnTypeNot.clear()
annotatedReturnTypeNot.addAll(it)
}
condition.annotatedReceiverType.takeIf { it.isNotEmpty() }?.let {
annotatedReceiverType.clear()
annotatedReceiverType.addAll(it)
}
condition.annotatedReceiverTypeNot.takeIf { it.isNotEmpty() }?.let {
annotatedReceiverTypeNot.clear()
annotatedReceiverTypeNot.addAll(it)
}
condition.annotatedParameterTypes.takeIf { it.isNotEmpty() }?.let {
annotatedParameterTypes.clear()
annotatedParameterTypes.addAll(it)
}
condition.annotatedParameterTypesNot.takeIf { it.isNotEmpty() }?.let {
annotatedParameterTypesNot.clear()
annotatedParameterTypesNot.addAll(it)
}
condition.annotatedExceptionTypes.takeIf { it.isNotEmpty() }?.let {
annotatedExceptionTypes.clear()
annotatedExceptionTypes.addAll(it)
}
condition.annotatedExceptionTypesNot.takeIf { it.isNotEmpty() }?.let {
annotatedExceptionTypesNot.clear()
annotatedExceptionTypesNot.addAll(it)
}
}
}
override val conditionStringMap
get() = super.conditionStringMap + mapOf(
PARAMETERS to parameters,
PARAMETERS_NOT to parametersNot,
PARAMETERS_CONDITION to parametersCondition,
PARAMETER_COUNT to parameterCount,
PARAMETER_COUNT_CONDITION to parameterCountCondition,
TYPE_PARAMETERS to typeParameters,
TYPE_PARAMETERS_NOT to typeParametersNot,
EXCEPTION_TYPES to exceptionTypes,
EXCEPTION_TYPES_NOT to exceptionTypesNot,
GENERIC_EXCEPTION_TYPES to genericExceptionTypes,
GENERIC_EXCEPTION_TYPES_NOT to genericExceptionTypesNot,
GENERIC_PARAMETERS to genericParameters,
GENERIC_PARAMETERS_NOT to genericParametersNot,
IS_VAR_ARGS to isVarArgs,
IS_VAR_ARGS_NOT to isVarArgsNot,
PARAMETER_ANNOTATIONS to parameterAnnotations,
PARAMETER_ANNOTATIONS_NOT to parameterAnnotationsNot,
ANNOTATED_RETURN_TYPE to annotatedReturnType,
ANNOTATED_RETURN_TYPE_NOT to annotatedReturnTypeNot,
ANNOTATED_RECEIVER_TYPE to annotatedReceiverType,
ANNOTATED_RECEIVER_TYPE_NOT to annotatedReceiverTypeNot,
ANNOTATED_PARAMETER_TYPES to annotatedParameterTypes,
ANNOTATED_PARAMETER_TYPES_NOT to annotatedParameterTypesNot,
ANNOTATED_EXCEPTION_TYPES to annotatedExceptionTypes,
ANNOTATED_EXCEPTION_TYPES_NOT to annotatedExceptionTypesNot
)
companion object {
const val PARAMETERS = "parameters"
const val PARAMETERS_NOT = "parametersNot"
const val PARAMETERS_CONDITION = "parametersCondition"
const val PARAMETER_COUNT = "parameterCount"
const val PARAMETER_COUNT_CONDITION = "parameterCountCondition"
const val TYPE_PARAMETERS = "typeParameters"
const val TYPE_PARAMETERS_NOT = "typeParametersNot"
const val EXCEPTION_TYPES = "exceptionTypes"
const val EXCEPTION_TYPES_NOT = "exceptionTypesNot"
const val GENERIC_EXCEPTION_TYPES = "genericExceptionTypes"
const val GENERIC_EXCEPTION_TYPES_NOT = "genericExceptionTypesNot"
const val GENERIC_PARAMETERS = "genericParameters"
const val GENERIC_PARAMETERS_NOT = "genericParametersNot"
const val IS_VAR_ARGS = "isVarArgs"
const val IS_VAR_ARGS_NOT = "isVarArgsNot"
const val PARAMETER_ANNOTATIONS = "parameterAnnotations"
const val PARAMETER_ANNOTATIONS_NOT = "parameterAnnotationsNot"
const val ANNOTATED_RETURN_TYPE = "annotatedReturnType"
const val ANNOTATED_RETURN_TYPE_NOT = "annotatedReturnTypeNot"
const val ANNOTATED_RECEIVER_TYPE = "annotatedReceiverType"
const val ANNOTATED_RECEIVER_TYPE_NOT = "annotatedReceiverTypeNot"
const val ANNOTATED_PARAMETER_TYPES = "annotatedParameterTypes"
const val ANNOTATED_PARAMETER_TYPES_NOT = "annotatedParameterTypesNot"
const val ANNOTATED_EXCEPTION_TYPES = "annotatedExceptionTypes"
const val ANNOTATED_EXCEPTION_TYPES_NOT = "annotatedExceptionTypesNot"
}
}

View File

@@ -0,0 +1,307 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("DuplicatedCode")
package com.highcapable.kavaref.condition.base
import com.highcapable.kavaref.condition.base.MemberCondition.Configuration.Optional
import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.kavaref.resolver.base.MemberResolver
import com.highcapable.kavaref.resolver.processor.MemberProcessor
import java.lang.reflect.AnnotatedElement
import java.lang.reflect.Executable
import java.lang.reflect.Field
import java.lang.reflect.Member
/**
* Base class for defining conditions on members [M], [R].
*
* [T] to specify the declaring class type of the member.
*/
abstract class MemberCondition<M : Member, R : MemberResolver<M, T>, T : Any> {
/**
* Configure initial conditions.
* @param declaringClass the class that declares the member.
* @param memberInstance the instance of the resolved member, default is null.
* @param processorResolver the resolver for processing members, if set,
* it will be used to resolve members instead of the default resolver.
* If you want to change the global processor resolver, you can set it using [MemberProcessor.globalResolver].
* @param superclass the superclass mode, which means that when the condition cannot find the corresponding member,
* it will search the [declaringClass]'s superclass, default is false.
* @param optional the optional mode, which means that when the condition cannot find the corresponding member,
* do not throw an exception or do not print any logs, but return an empty list, default is [Optional.NO].
*/
data class Configuration<T : Any>(
val declaringClass: Class<T>,
val memberInstance: T? = null,
var processorResolver: MemberProcessor.Resolver? = null,
var superclass: Boolean = false,
var optional: Optional = Optional.NO
) {
/**
* Optional mode for handling member resolution.
*/
enum class Optional {
/** Do not use optional mode. */
NO,
/**
* Enable optional mode to minimize exception prompts (do not throw
* exceptions), but the warning log will still be printed.
*/
NOTICE,
/**
* Enable optional mode to minimize exception prompts (do not throw
* exceptions) and do not print any logs.
*/
SILENT
}
companion object {
/**
* Create a new instance of [Configuration].
* @return [Configuration]
*/
@JvmStatic
@JvmOverloads
fun <T : Any> Class<T>.createConfiguration(
memberInstance: T? = null,
processorResolver: MemberProcessor.Resolver? = null,
superclass: Boolean = false,
optional: Optional = Optional.NO
) = Configuration(declaringClass = this, memberInstance, processorResolver, superclass, optional)
}
}
/**
* The configuration of this condition,
* user can only set by [build] function.
*/
@get:JvmSynthetic
@set:JvmSynthetic
internal var configuration: Configuration<T>? = null
/** @see Member.getName */
var name: String? = null
/** @see Member.getName */
var nameCondition: ((String) -> Boolean)? = null
/** @see Member.getModifiers */
val modifiers = mutableSetOf<Modifiers>()
/** @see Member.getModifiers */
val modifiersNot = mutableSetOf<Modifiers>()
/** @see Member.getModifiers */
var modifiersCondition: ((Set<Modifiers>) -> Boolean)? = null
/** @see Member.isSynthetic */
var isSynthetic: Boolean? = null
/** @see Member.isSynthetic */
var isSyntheticNot: Boolean? = null
/** @see AnnotatedElement.getDeclaredAnnotations */
val annotations = mutableSetOf<Any>()
/** @see AnnotatedElement.getDeclaredAnnotations */
val annotationsNot = mutableSetOf<Any>()
/**
* @see Executable.toGenericString
* @see Field.toGenericString
*/
var genericString: String? = null
/** @see Member.getName */
open fun name(name: String) = apply {
this.name = name
}
/** @see Member.getName */
open fun name(condition: (String) -> Boolean) = apply {
this.nameCondition = condition
}
/** @see Member.getModifiers */
open fun modifiers(vararg modifiers: Modifiers) = apply {
this.modifiers.addAll(modifiers)
}
/** @see Member.getModifiers */
open fun modifiersNot(vararg modifiers: Modifiers) = apply {
this.modifiersNot.addAll(modifiers)
}
/** @see Member.getModifiers */
open fun modifiers(condition: (Set<Modifiers>) -> Boolean) = apply {
this.modifiersCondition = condition
}
/** @see Member.isSynthetic */
open fun isSynthetic(isSynthetic: Boolean) = apply {
this.isSynthetic = isSynthetic
}
/** @see Member.isSynthetic */
open fun isSyntheticNot(isSynthetic: Boolean) = apply {
this.isSyntheticNot = isSynthetic
}
/** @see AnnotatedElement.getDeclaredAnnotations */
open fun annotations(vararg annotations: Any) = apply {
this.annotations.addAll(annotations.toList())
}
/** @see AnnotatedElement.getDeclaredAnnotations */
open fun annotationsNot(vararg annotations: Any) = apply {
this.annotationsNot.addAll(annotations.toList())
}
/**
* @see Executable.toGenericString
* @see Field.toGenericString
*/
open fun genericString(genericString: String) = apply {
this.genericString = genericString
}
/**
* Enable superclass mode.
* @see Configuration.superclass
*/
open fun superclass() = apply {
configuration?.superclass = true
}
/**
* Initialize the copied data from this condition to the new condition.
* @param newSelf the new condition instance.
*/
protected open fun initializeCopiedData(newSelf: MemberCondition<M, R, T>) {
newSelf.name = name
newSelf.nameCondition = nameCondition
newSelf.modifiers.addAll(modifiers)
newSelf.modifiersNot.addAll(modifiersNot)
newSelf.isSynthetic = isSynthetic
newSelf.isSyntheticNot = isSyntheticNot
newSelf.annotations.addAll(annotations)
newSelf.annotationsNot.addAll(annotationsNot)
newSelf.genericString = genericString
}
/**
* Initialize the merged data from this condition to the new condition.
* @param other the other condition instance to merge with.
*/
@JvmSynthetic
internal open fun initializeMergedData(other: MemberCondition<M, R, T>) {
other.name?.let { name = it }
other.nameCondition?.let { nameCondition = it }
other.modifiers.takeIf { it.isNotEmpty() }?.let {
modifiers.clear()
modifiers.addAll(it)
}
other.modifiersNot.takeIf { it.isNotEmpty() }?.let {
modifiersNot.clear()
modifiersNot.addAll(it)
}
other.isSynthetic?.let { isSynthetic = it }
other.isSyntheticNot?.let { isSyntheticNot = it }
other.annotations.takeIf { it.isNotEmpty() }?.let {
annotations.clear()
annotations.addAll(it)
}
other.annotationsNot.takeIf { it.isNotEmpty() }?.let {
annotationsNot.clear()
annotationsNot.addAll(it)
}
other.genericString?.let { genericString = it }
}
/**
* Create a copy of this condition.
* @return [MemberCondition]<[M], [R], [T]>
*/
abstract fun copy(): MemberCondition<M, R, T>
/**
* Build the condition with the given [configuration].
*
* - Note: If you are not a manually created condition instance, then you cannot set [configuration] again.
* @param configuration the class that declares the member.
* @return [List]<[R]>
*/
@JvmOverloads
open fun build(configuration: Configuration<T>? = null): List<R> =
TODO("Implemented build function in subclass.")
/**
* Get the condition string map.
* @return [Map]<[String], [Any] or null>
*/
@get:JvmSynthetic
internal open val conditionStringMap get() = mapOf(
NAME to name,
NAME_CONDITION to nameCondition,
MODIFIERS to modifiers,
MODIFIERS_NOT to modifiersNot,
MODIFIERS_CONDITION to modifiersCondition,
IS_SYNTHETIC to isSynthetic,
IS_SYNTHETIC_NOT to isSyntheticNot,
ANNOTATIONS to annotations,
ANNOTATIONS_NOT to annotationsNot,
GENERIC_STRING to genericString
)
companion object {
const val NAME = "name"
const val NAME_CONDITION = "nameCondition"
const val MODIFIERS = "modifiers"
const val MODIFIERS_NOT = "modifiersNot"
const val MODIFIERS_CONDITION = "modifiersCondition"
const val IS_SYNTHETIC = "isSynthetic"
const val IS_SYNTHETIC_NOT = "isSyntheticNot"
const val ANNOTATIONS = "annotations"
const val ANNOTATIONS_NOT = "annotationsNot"
const val GENERIC_STRING = "genericString"
}
/**
* Check if the [configuration] is null and set it.
* If the [configuration] is not null, throw an exception.
* @param configuration the configuration to set.
* @throws IllegalStateException if the [configuration] is not null.
*/
protected fun checkAndSetConfiguration(configuration: Configuration<T>) {
check(this.configuration == null) {
"Configuration already set for this condition \"$javaClass\" of \"${this.configuration}\". " +
"To prevent problems, the configuration can only be set once in a condition, " +
"otherwise use copy() to reuse the condition."
}; this.configuration = configuration
}
}

View File

@@ -0,0 +1,35 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/6/20.
*/
@file:Suppress("unused")
package com.highcapable.kavaref.condition.extension
import com.highcapable.kavaref.condition.base.MemberCondition
import com.highcapable.kavaref.resolver.base.MemberResolver
import java.lang.reflect.Member
/**
* Merge this condition with another [other] condition.
* @receiver the condition to merge from.
* @param other the other condition to merge with.
*/
infix fun <M : Member, R : MemberResolver<M, T>, T : Any, U : MemberCondition<M, R, T>> U.mergeWith(other: U) = initializeMergedData(other)

View File

@@ -0,0 +1,36 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
package com.highcapable.kavaref.condition.matcher
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import java.lang.reflect.Type
/**
* A [TypeMatcher] that matches a specific class type.
* @param clazz the class type to match.
*/
data class ClassTypeMatcher(
val clazz: Class<*>
) : TypeMatcher {
override fun matches(type: Type) = type == clazz
}

View File

@@ -0,0 +1,43 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
package com.highcapable.kavaref.condition.matcher
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import java.lang.reflect.GenericArrayType
import java.lang.reflect.Type
/**
* A [TypeMatcher] that matches a generic array type.
* @see GenericArrayType.getGenericComponentType
* @see Class.getComponentType
* @param componentMatcher the [TypeMatcher] for the component type of the array.
*/
data class GenericArrayTypeMatcher(
val componentMatcher: TypeMatcher
) : TypeMatcher {
override fun matches(type: Type) = when (type) {
is GenericArrayType -> componentMatcher.matches(type.genericComponentType)
is Class<*> -> type.isArray && componentMatcher.matches(type.componentType)
else -> false
}
}

View File

@@ -0,0 +1,48 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
package com.highcapable.kavaref.condition.matcher
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.condition.matcher.extension.matchesAll
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type
/**
* A [TypeMatcher] that matches a parameterized type.
* @see ParameterizedType.getRawType
* @see ParameterizedType.getActualTypeArguments
* @param rawType the raw type of the parameterized type.
* @param arguments the [TypeMatcher]s for the type arguments of the parameterized type.
*/
data class ParameterizedTypeMatcher(
val rawType: Class<*>,
val arguments: List<TypeMatcher>
) : TypeMatcher {
override fun matches(type: Type): Boolean {
if (type !is ParameterizedType) return false
if (type.rawType != rawType) return false
val args = type.actualTypeArguments
return args.toList().matchesAll(arguments)
}
}

View File

@@ -0,0 +1,38 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
package com.highcapable.kavaref.condition.matcher
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import java.lang.reflect.Type
import java.lang.reflect.TypeVariable
/**
* A [TypeMatcher] that matches a type variable.
* @see TypeVariable.getName
* @param name the name of the type variable.
*/
data class TypeVariableMatcher(
val name: String
) : TypeMatcher {
override fun matches(type: Type) = type is TypeVariable<*> && type.name == name
}

View File

@@ -0,0 +1,48 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
@file:Suppress("unused")
package com.highcapable.kavaref.condition.matcher
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.condition.matcher.extension.matchesAll
import java.lang.reflect.Type
import java.lang.reflect.WildcardType
/**
* A [TypeMatcher] that matches a wildcard type.
* @see WildcardType.getUpperBounds
* @see WildcardType.getLowerBounds
* @param upperBounds the upper bounds of the wildcard type.
* @param lowerBounds the lower bounds of the wildcard type.
*/
data class WildcardTypeMatcher(
val upperBounds: List<TypeMatcher> = emptyList(),
val lowerBounds: List<TypeMatcher> = emptyList()
) : TypeMatcher {
override fun matches(type: Type): Boolean {
if (type !is WildcardType) return false
return type.upperBounds.toList().matchesAll(upperBounds) &&
type.lowerBounds.toList().matchesAll(lowerBounds)
}
}

View File

@@ -0,0 +1,37 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
package com.highcapable.kavaref.condition.matcher.base
import java.lang.reflect.Type
/**
* Base interface for type matchers.
*/
interface TypeMatcher {
/**
* Check if the type matches the given [type].
* @param type the type to check.
* @return [Boolean]
*/
fun matches(type: Type): Boolean
}

View File

@@ -0,0 +1,89 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/20.
*/
@file:Suppress("unused")
package com.highcapable.kavaref.condition.matcher.extension
import com.highcapable.kavaref.condition.matcher.ClassTypeMatcher
import com.highcapable.kavaref.condition.matcher.GenericArrayTypeMatcher
import com.highcapable.kavaref.condition.matcher.ParameterizedTypeMatcher
import com.highcapable.kavaref.condition.matcher.TypeVariableMatcher
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import java.lang.reflect.Type
import kotlin.reflect.KClass
/**
* Creates a [TypeMatcher] for a specific class type.
* @param name the name of the type variable.
* @return [TypeVariableMatcher]
*/
fun typeVar(name: String) = TypeVariableMatcher(name)
/**
* Converts a [Class] to a [ClassTypeMatcher].
* @receiver [Class]
* @return [ClassTypeMatcher]
*/
fun Class<*>.toTypeMatcher() = ClassTypeMatcher(clazz = this)
/**
* Converts a [KClass.java] to a [ClassTypeMatcher].
* @receiver [KClass]
* @return [ClassTypeMatcher]
*/
fun KClass<*>.toTypeMatcher() = java.toTypeMatcher()
/**
* Creates a [ParameterizedTypeMatcher] for a specific [Class] type with the given type arguments.
* @receiver [Class]
* @param arguments the type arguments for the parameterized type.
* @return [ParameterizedTypeMatcher]
*/
fun Class<*>.parameterizedBy(vararg arguments: TypeMatcher) =
ParameterizedTypeMatcher(rawType = this, arguments.toList())
/**
* Creates a [ParameterizedTypeMatcher] for a specific [KClass.java] type with the given type arguments.
* @receiver [KClass]
* @param arguments the type arguments for the parameterized type.
* @return [ParameterizedTypeMatcher]
*/
fun KClass<*>.parameterizedBy(vararg arguments: TypeMatcher) = java.parameterizedBy(*arguments)
/**
* Creates a [GenericArrayTypeMatcher] from [TypeMatcher].
* @receiver [TypeMatcher]
* @return [GenericArrayTypeMatcher]
*/
fun TypeMatcher.asGenericArray() = GenericArrayTypeMatcher(componentMatcher = this)
/**
* Check if the list of [Type] matches all the given [TypeMatcher].
* @receiver the list of [Type] to be checked.
* @param matchers the list of [TypeMatcher] to be checked.
* @return [Boolean]
*/
@JvmSynthetic
internal fun List<Type>.matchesAll(matchers: List<TypeMatcher>): Boolean {
if (this.size != matchers.size) return false
return this.zip(matchers).all { (t, m) -> m.matches(t) }
}

View File

@@ -0,0 +1,62 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("unused")
package com.highcapable.kavaref.condition.type
import java.lang.reflect.Modifier
/**
* Modifiers for Java reflection.
* @param mod the modifier bitmask.
*/
enum class Modifiers(private val mod: Int) {
PUBLIC(Modifier.PUBLIC),
PRIVATE(Modifier.PRIVATE),
PROTECTED(Modifier.PROTECTED),
STATIC(Modifier.STATIC),
FINAL(Modifier.FINAL),
SYNCHRONIZED(Modifier.SYNCHRONIZED),
VOLATILE(Modifier.VOLATILE),
TRANSIENT(Modifier.TRANSIENT),
NATIVE(Modifier.NATIVE),
INTERFACE(Modifier.INTERFACE),
ABSTRACT(Modifier.ABSTRACT),
STRICT(Modifier.STRICT);
/**
* Check if the modifier matches the given modifier.
* @param modifier the modifier bitmask to check against.
* @return [Boolean]
*/
fun matches(modifier: Int) = (mod and modifier) != 0
companion object {
/**
* Get the set of modifiers that match the given modifier bitmask.
* @param modifier the modifier bitmask to check against.
* @return [Set]<[Modifiers]>
*/
fun matching(modifier: Int) = entries.filter { it.matches(modifier) }.toSet()
}
}

View File

@@ -0,0 +1,69 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
package com.highcapable.kavaref.condition.type
import com.highcapable.kavaref.extension.classOf
import kotlin.reflect.KClass
/**
* You can fill this type in the reflection lookup condition as a placeholder.
*
* It is a vague type that you can use when the signature of the JVM type is too long and does not want to declare a type.
*
* Usage:
*
* ```
* public void a(java.lang.String, some.name.like.too.long.Type, int);
* ```
*
* ```kotlin
* method {
* name = "a"
* parameters(String::class, VagueType, Int::class)
* }
*/
object VagueType {
private const val TAG = "VagueType"
/**
* Format the placeholder to a string.
* @param placeholder the placeholder to be formatted.
* @return [String]
*/
@JvmSynthetic
internal fun format(placeholder: Any?): String? = when (placeholder) {
null -> null
is VagueType -> TAG
is Class<*> -> if (placeholder != classOf<VagueType>())
placeholder.toString()
else TAG
is KClass<*> -> if (placeholder != VagueType::class)
placeholder.toString()
else TAG
is Collection<*> ->
placeholder.map {
if (it != null) format(it) else null
}.toString()
else -> placeholder.toString()
}
}

View File

@@ -0,0 +1,84 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package com.highcapable.kavaref.resolver
import com.highcapable.kavaref.extension.classOf
import com.highcapable.kavaref.extension.makeAccessible
import com.highcapable.kavaref.resolver.base.MemberResolver
import java.lang.reflect.Constructor
/**
* Resolving [Constructor].
* @param self the member to be resolved.
*/
class ConstructorResolver<T : Any> internal constructor(override val self: Constructor<T>) : MemberResolver<Constructor<T>, T>(self) {
override fun copy() = ConstructorResolver(self)
/**
* Create a new instance of the class represented by this constructor.
* @see Constructor.newInstance
* @see createQuietly
* @see createAsType
* @see createAsTypeQuietly
* @return [T]
*/
fun create(vararg args: Any?): T {
self.makeAccessible()
return self.newInstance(*args)
}
/**
* Create a new instance of the class represented by this constructor and cast it to the specified type [T].
* @see Constructor.newInstance
* @see createAsTypeQuietly
* @see createQuietly
* @return [T]
*/
inline fun <reified T : Any> createAsType(vararg args: Any?): T {
self.makeAccessible()
return self.newInstance(*args) as? T ?: error("$this's instance cannot be cast to type ${classOf<T>()}.")
}
/**
* Create a new instance of the class represented by this constructor and ignore any exceptions.
* @see Constructor.newInstance
* @see create
* @see createAsType
* @see createAsTypeQuietly
* @return [T] or null.
*/
fun createQuietly(vararg args: Any?) = runCatching { create(*args) }.getOrNull()
/**
* Create a new instance of the class represented by this constructor and cast it to the
* specified type [T] and ignore any exceptions.
* @see Constructor.newInstance
* @see create
* @see createAsType
* @see createQuietly
* @return [T] or null.
*/
inline fun <reified T : Any> createAsTypeQuietly(vararg args: Any?) = runCatching { createAsType<T>(*args) }.getOrNull()
}

View File

@@ -0,0 +1,100 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("UNCHECKED_CAST", "MemberVisibilityCanBePrivate")
package com.highcapable.kavaref.resolver
import com.highcapable.kavaref.extension.makeAccessible
import com.highcapable.kavaref.resolver.base.InstanceAwareResolver
import java.lang.reflect.Field
/**
* Resolving [Field].
* @param self the member to be resolved.
*/
class FieldResolver<T : Any> internal constructor(override val self: Field) : InstanceAwareResolver<Field, T>(self) {
override fun of(instance: T?) = apply {
checkAndSetInstance(instance)
}
override fun copy() = FieldResolver<T>(self)
/**
* Get the value of the field.
* @see Field.get
* @see getQuietly
* @return [T] or null.
*/
@JvmName("getTyped")
fun <T : Any?> get(): T? {
self.makeAccessible()
return self.get(instance) as? T?
}
/**
* Get the value of the field and ignore any exceptions.
* @see Field.get
* @see get
* @return [T] or null.
*/
@JvmName("getQuietlyTyped")
fun <T : Any?> getQuietly() = runCatching { get<T>() }.getOrNull()
/**
* Get the value of the field.
* @see Field.get
* @see getQuietly
* @return [Any] or null.
*/
fun get(): Any? {
self.makeAccessible()
return self.get(instance)
}
/**
* Get the value of the field and ignore any exceptions.
* @see Field.get
* @see get
* @return [Any] or null.
*/
fun getQuietly() = runCatching { get() }.getOrNull()
/**
* Set the value of the field.
* @see Field.set
* @see setQuietly
* @param value the value to set.
*/
fun set(value: Any?) {
self.makeAccessible()
self.set(instance, value)
}
/**
* Set the value of the field and ignore any exceptions.
* @see Field.set
* @see set
* @param value the value to set.
*/
fun setQuietly(value: Any?) = runCatching { set(value) }.getOrNull() ?: Unit
}

View File

@@ -0,0 +1,81 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("UNCHECKED_CAST", "MemberVisibilityCanBePrivate")
package com.highcapable.kavaref.resolver
import com.highcapable.kavaref.extension.makeAccessible
import com.highcapable.kavaref.resolver.base.InstanceAwareResolver
import java.lang.reflect.Method
/**
* Resolving [Method].
* @param self the member to be resolved.
*/
class MethodResolver<T : Any> internal constructor(override val self: Method) : InstanceAwareResolver<Method, T>(self) {
override fun of(instance: T?) = apply {
checkAndSetInstance(instance)
}
override fun copy() = MethodResolver<T>(self)
/**
* Invoke the method with the given arguments.
* @see Method.invoke
* @see invokeQuietly
* @return [T] or null.
*/
@JvmName("invokeTyped")
fun <T : Any?> invoke(vararg args: Any?): T? {
self.makeAccessible()
return self.invoke(instance, *args) as? T?
}
/**
* Invoke the method with the given arguments and ignore any exceptions.
* @see Method.invoke
* @see invokeQuietly
* @return [T] or null.
*/
@JvmName("invokeQuietlyTyped")
fun <T : Any?> invokeQuietly(vararg args: Any?) = runCatching { invoke<T>(*args) }.getOrNull()
/**
* Invoke the method with the given arguments.
* @see Method.invoke
* @see invoke
* @return [Any] or null.
*/
fun invoke(vararg args: Any?): Any? {
self.makeAccessible()
return self.invoke(instance, *args)
}
/**
* Invoke the method with the given arguments and ignore any exceptions.
* @see Method.invoke
* @see invoke
* @return [Any] or null.
*/
fun invokeQuietly(vararg args: Any?) = runCatching { invoke(*args) }.getOrNull()
}

View File

@@ -0,0 +1,65 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
package com.highcapable.kavaref.resolver.base
import com.highcapable.kavaref.condition.base.MemberCondition
import java.lang.reflect.Member
/**
* Base [instance] aware class for resolving member [M].
*
* [T] to specify the declaring class type of the member.
* @param self the member to be resolved.
*/
abstract class InstanceAwareResolver<M : Member, T : Any>(override val self: M) : MemberResolver<M, T>(self) {
/** The instance of [self]. */
@get:JvmSynthetic
@set:JvmSynthetic
internal var instance: T? = null
/**
* Set the instance of [self].
*
* If you have already set it in [MemberCondition.Configuration.memberInstance],
* then there is no need to set it here.
* If you want to reuse the resolver, please use [copy] to create a new resolver.
* @param instance the instance to set.
*/
abstract fun of(instance: T?): InstanceAwareResolver<M, T>
/**
* Check if the [instance] is null and set it.
* If the [instance] is not null, throw an exception.
* @param instance the instance to set.
* @throws IllegalStateException if the [instance] is not null.
*/
protected fun checkAndSetInstance(instance: T?) {
check(this.instance == null) {
"Instance already set for this resolver \"$javaClass\" of \"$self(${this.instance})\". " +
"To prevent problems, the instance object can only be set once in a resolver, " +
"otherwise use copy() to reuse the resolver."
}
this.instance = instance
}
}

View File

@@ -0,0 +1,39 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
package com.highcapable.kavaref.resolver.base
import java.lang.reflect.Member
/**
* Base class for resolving member [M].
*
* [T] to specify the declaring class type of the member.
* @param self the member to be resolved.
*/
abstract class MemberResolver<M : Member, T : Any>(open val self: M) {
/**
* Create a copy of this resolver.
* @return [MemberResolver]<[M]>
*/
abstract fun copy(): MemberResolver<M, T>
}

View File

@@ -0,0 +1,518 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/16.
*/
@file:Suppress("UNCHECKED_CAST", "UnnecessaryVariable")
package com.highcapable.kavaref.resolver.processor
import com.highcapable.kavaref.condition.ConstructorCondition
import com.highcapable.kavaref.condition.FieldCondition
import com.highcapable.kavaref.condition.MethodCondition
import com.highcapable.kavaref.condition.base.ExecutableCondition
import com.highcapable.kavaref.condition.base.MemberCondition
import com.highcapable.kavaref.condition.matcher.base.TypeMatcher
import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.kavaref.condition.type.VagueType
import com.highcapable.kavaref.extension.classOf
import com.highcapable.kavaref.extension.toClass
import com.highcapable.kavaref.extension.toClassOrNull
import com.highcapable.kavaref.generated.KavarefCoreProperties
import com.highcapable.kavaref.resolver.ConstructorResolver
import com.highcapable.kavaref.resolver.FieldResolver
import com.highcapable.kavaref.resolver.MethodResolver
import com.highcapable.kavaref.resolver.base.InstanceAwareResolver
import com.highcapable.kavaref.resolver.base.MemberResolver
import com.highcapable.kavaref.runtime.KavaRefRuntime
import java.lang.reflect.AnnotatedElement
import java.lang.reflect.Constructor
import java.lang.reflect.Executable
import java.lang.reflect.Field
import java.lang.reflect.Member
import java.lang.reflect.Method
import java.lang.reflect.Type
import kotlin.reflect.KClass
/**
* Processing member resolver core implementation.
*/
object MemberProcessor {
private const val PRODUCT_DESCRIPTION = "\n====== Generated by KavaRef ${KavarefCoreProperties.PROJECT_KAVAREF_CORE_VERSION} ======\n"
/**
* Global [Resolver] used by KavaRef to resolve members.
*
* You can change this resolver to use a custom member resolver, which will affect global behavior.
*/
@JvmStatic
var globalResolver: Resolver = Resolver()
/**
* Resolver class for resolving members.
*
* Provides methods to resolve fields, methods, and constructors of a class.
*
* You can inherit this class to implement a custom member parser,
* and override the [getDeclaredFields], [getDeclaredMethods] and
* [getDeclaredConstructors] methods to implement custom member resolution logic.
*/
open class Resolver {
/**
* Resolve fields of the specified class [T].
* @param declaringClass the class to resolve fields from.
* @return [List]<[Field]>
*/
open fun <T : Any> getDeclaredFields(declaringClass: Class<T>): List<Field> =
runCatching { declaringClass.declaredFields.toList() }.onFailure {
KavaRefRuntime.warn("Failed to get declared fields in $this because got an exception.", it)
}.getOrNull() ?: emptyList()
/**
* Resolve methods of the specified class [T].
* @param declaringClass the class to resolve methods from.
* @return [List]<[Method]>
*/
open fun <T : Any> getDeclaredMethods(declaringClass: Class<T>): List<Method> =
runCatching { declaringClass.declaredMethods.toList() }.onFailure {
KavaRefRuntime.warn("Failed to get declared methods in $this because got an exception.", it)
}.getOrNull() ?: emptyList()
/**
* Resolve constructors of the specified class [T].
* @param declaringClass the class to resolve constructors from.
* @return [List]<[Constructor]<[T]>>
*/
open fun <T : Any> getDeclaredConstructors(declaringClass: Class<T>): List<Constructor<T>> =
runCatching { declaringClass.declaredConstructors.filterIsInstance<Constructor<T>>() }.onFailure {
KavaRefRuntime.warn("Failed to get declared constructors in $this because got an exception.", it)
}.getOrNull() ?: emptyList()
}
/**
* Resolve members with current [condition] and [configuration].
* @param condition the condition to resolve members.
* @param configuration the configuration to resolve members, must not be null.
* @return [List]<[R]>
*/
internal inline fun <reified M : Member, reified R : MemberResolver<M, T>, T : Any> resolve(
condition: MemberCondition<M, R, T>,
configuration: MemberCondition.Configuration<T>?
): List<R> {
require(configuration != null) {
"You must provide a configuration to resolve the member use build(configuration)."
}
return when (condition) {
is MethodCondition -> resolveInClass(
condition, configuration, configuration.declaringClass
) { declaringClass ->
methodFilters(condition, configuration, declaringClass)
}
is ConstructorCondition -> resolveInClass(
condition, configuration, configuration.declaringClass
) { declaringClass ->
constructorFilters(condition, configuration, declaringClass)
}
is FieldCondition -> resolveInClass(
condition, configuration, configuration.declaringClass
) { declaringClass ->
fieldFilters(condition, configuration, declaringClass)
}
else -> error("Unsupported condition type: $condition")
} as List<R>
}
private fun <M : Member, R : MemberResolver<M, T>, T : Any> resolveInClass(
condition: MemberCondition<M, R, T>,
configuration: MemberCondition.Configuration<T>,
declaringClass: Class<*>?,
result: (declaringClass: Class<*>) -> List<R>
): List<R> {
if (declaringClass == null || declaringClass == classOf<Any>())
return throwIfNotOptional(condition, configuration)
return result(declaringClass).ifEmpty {
if (configuration.superclass)
resolveInClass(condition, configuration, declaringClass.superclass, result)
else throwIfNotOptional(condition, configuration)
}
}
private fun <T : Any> methodFilters(
condition: MethodCondition<T>,
configuration: MemberCondition.Configuration<T>,
declaringClass: Class<*>
): List<MethodResolver<T>> = configuration.currentProcessorResolver.getDeclaredMethods(declaringClass)
.asSequence()
.baseFilters(condition, configuration)
.executableFilters(condition, configuration)
.filter(configuration, MethodCondition.RETURN_TYPE, condition.returnType) { key, value ->
value.returnType == key.toTypeClass(configuration, noVague = "Method: returnType")
}
.filter(configuration, MethodCondition.RETURN_TYPE_CONDITION, condition.returnTypeCondition) { key, value ->
runOrElse { key(value.returnType) }
}
.filter(configuration, MethodCondition.IS_BRIDGE, condition.isBridge) { key, value -> value.isBridge == key }
.filter(configuration, MethodCondition.IS_BRIDGE_NOT, condition.isBridgeNot) { key, value -> value.isBridge != key }
.filter(configuration, MethodCondition.IS_DEFAULT, condition.isDefault) { key, value -> value.isDefault == key }
.filter(configuration, MethodCondition.IS_DEFAULT_NOT, condition.isDefaultNot) { key, value -> value.isDefault != key }
.resolve(configuration)
private fun <T : Any> constructorFilters(
condition: ConstructorCondition<T>,
configuration: MemberCondition.Configuration<T>,
declaringClass: Class<*>
): List<ConstructorResolver<T>> = configuration.currentProcessorResolver.getDeclaredConstructors(declaringClass)
.asSequence()
.baseFilters(condition, configuration)
.executableFilters(condition, configuration)
.resolve(configuration)
private fun <T : Any> fieldFilters(
condition: FieldCondition<T>,
configuration: MemberCondition.Configuration<T>,
declaringClass: Class<*>
): List<FieldResolver<T>> = configuration.currentProcessorResolver.getDeclaredFields(declaringClass)
.asSequence()
.baseFilters(condition, configuration)
.filter(configuration, FieldCondition.IS_ENUM_CONSTANT, condition.isEnumConstant) { key, value -> value.isEnumConstant == key }
.filter(configuration, FieldCondition.IS_ENUM_CONSTANT_NOT, condition.isEnumConstantNot) { key, value -> value.isEnumConstant != key }
.filter(configuration, FieldCondition.TYPE, condition.type) { key, value ->
value.type == key.toTypeClass(configuration, noVague = "Field: type")
}
.filter(configuration, FieldCondition.TYPE_CONDITION, condition.typeCondition) { key, value -> key(value.type) }
.filter(configuration, FieldCondition.GENERIC_TYPE, condition.genericType) { key, value -> key.matches(value.genericType) }
.filter(configuration, FieldCondition.GENERIC_TYPE_CONDITION, condition.genericTypeCondition) { key, value -> key(value.genericType) }
.resolve(configuration)
private fun <M : Member, T : Any> Sequence<M>.baseFilters(
condition: MemberCondition<*, *, *>,
configuration: MemberCondition.Configuration<T>
) = this.filter(configuration, MemberCondition.NAME, condition.name) { key, value -> value.name == key }
.filter(configuration, MemberCondition.NAME_CONDITION, condition.nameCondition) { key, value -> runOrElse { key(value.name) } }
.filter(configuration, MemberCondition.MODIFIERS, condition.modifiers) { key, value ->
key.all { it.matches(value.modifiers) }
}
.filter(configuration, MemberCondition.MODIFIERS_NOT, condition.modifiersNot) { key, value ->
key.none { it.matches(value.modifiers) }
}
.filter(configuration, MemberCondition.MODIFIERS_CONDITION, condition.modifiersCondition) { key, value ->
runOrElse { key(Modifiers.matching(value.modifiers)) }
}
.filter(configuration, MemberCondition.IS_SYNTHETIC, condition.isSynthetic) { key, value -> value.isSynthetic == key }
.filter(configuration, MemberCondition.IS_SYNTHETIC_NOT, condition.isSyntheticNot) { key, value -> value.isSynthetic != key }
.filter(configuration, MemberCondition.ANNOTATIONS, condition.annotations) { key, value ->
val annotations = value.annotations.map { it.annotationClass.java }
compareElementTypes(key, annotations, configuration)
}
.filter(configuration, MemberCondition.ANNOTATIONS_NOT, condition.annotationsNot) { key, value ->
val annotations = value.annotations.map { it.annotationClass.java }
!compareElementTypes(key, annotations, configuration)
}
.filter(configuration, MemberCondition.GENERIC_STRING, condition.genericString) { key, value -> value.toGenericString() == key }
private fun <M : Executable, T : Any> Sequence<M>.executableFilters(
condition: ExecutableCondition<*, *, *>,
configuration: MemberCondition.Configuration<T>
) = this
.filter(configuration, ExecutableCondition.PARAMETERS, condition.parameters) { key, value ->
compareElementTypes(key, value.parameterTypes.toList(), configuration)
}
.filter(configuration, ExecutableCondition.PARAMETERS_NOT, condition.parametersNot) { key, value ->
!compareElementTypes(key, value.parameterTypes.toList(), configuration)
}
.filter(configuration, ExecutableCondition.PARAMETERS_CONDITION, condition.parametersCondition) { key, value ->
runOrElse { key(value.parameterTypes.toList()) }
}
.filter(configuration, ExecutableCondition.PARAMETER_COUNT, condition.parameterCount) { key, value -> value.parameterCount == key }
.filter(configuration, ExecutableCondition.PARAMETER_COUNT_CONDITION, condition.parameterCountCondition) { key, value ->
runOrElse { key(value.parameterCount) }
}
.filter(configuration, ExecutableCondition.TYPE_PARAMETERS, condition.typeParameters) { key, value ->
compareMatcherTypes(key, value.typeParameters.toList())
}
.filter(configuration, ExecutableCondition.TYPE_PARAMETERS_NOT, condition.typeParametersNot) { key, value ->
!compareMatcherTypes(key, value.typeParameters.toList())
}
.filter(configuration, ExecutableCondition.EXCEPTION_TYPES, condition.exceptionTypes) { key, value ->
compareElementTypes(key, value.exceptionTypes.toList(), configuration)
}
.filter(configuration, ExecutableCondition.EXCEPTION_TYPES_NOT, condition.exceptionTypesNot) { key, value ->
!compareElementTypes(key, value.exceptionTypes.toList(), configuration)
}
.filter(configuration, ExecutableCondition.GENERIC_EXCEPTION_TYPES, condition.genericExceptionTypes) { key, value ->
compareMatcherTypes(key, value.genericExceptionTypes.toList())
}
.filter(configuration, ExecutableCondition.GENERIC_EXCEPTION_TYPES_NOT, condition.genericExceptionTypesNot) { key, value ->
!compareMatcherTypes(key, value.genericExceptionTypes.toList())
}
.filter(configuration, ExecutableCondition.GENERIC_PARAMETERS, condition.genericParameters) { key, value ->
compareMatcherTypes(key, value.genericParameterTypes.toList())
}
.filter(configuration, ExecutableCondition.GENERIC_PARAMETERS_NOT, condition.genericParametersNot) { key, value ->
!compareMatcherTypes(key, value.genericParameterTypes.toList())
}
.filter(configuration, ExecutableCondition.IS_VAR_ARGS, condition.isVarArgs) { key, value -> value.isVarArgs == key }
.filter(configuration, ExecutableCondition.IS_VAR_ARGS_NOT, condition.isVarArgsNot) { key, value -> value.isVarArgs != key }
.filter(configuration, ExecutableCondition.PARAMETER_ANNOTATIONS, condition.parameterAnnotations) { key, value ->
val annotations = value.parameterAnnotations.map { it.map { e -> e.annotationClass.java } }
compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.PARAMETER_ANNOTATIONS_NOT, condition.parameterAnnotationsNot) { key, value ->
val annotations = value.parameterAnnotations.map { it.map { e -> e.annotationClass.java } }
!compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_RETURN_TYPE, condition.annotatedReturnType) { key, value ->
val annotations = value.annotatedReturnType.annotations.map { it.annotationClass.java }
compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_RETURN_TYPE_NOT, condition.annotatedReturnTypeNot) { key, value ->
val annotations = value.annotatedReturnType.annotations.map { it.annotationClass.java }
!compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_RECEIVER_TYPE, condition.annotatedReceiverType) { key, value ->
val annotations = value.annotatedReceiverType.annotations.map { it.annotationClass.java }
compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_RECEIVER_TYPE_NOT, condition.annotatedReceiverTypeNot) { key, value ->
val annotations = value.annotatedReceiverType.annotations.map { it.annotationClass.java }
!compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_PARAMETER_TYPES, condition.annotatedParameterTypes) { key, value ->
val annotations = value.annotatedParameterTypes.map { it.annotations.map { e -> e.annotationClass.java } }.flatten()
compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_PARAMETER_TYPES_NOT, condition.annotatedParameterTypesNot) { key, value ->
val annotations = value.annotatedParameterTypes.map { it.annotations.map { e -> e.annotationClass.java } }.flatten()
!compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_EXCEPTION_TYPES, condition.annotatedExceptionTypes) { key, value ->
val annotations = value.annotatedExceptionTypes.map { it.annotations.map { e -> e.annotationClass.java } }.flatten()
compareElementTypes(key, annotations, configuration)
}
.filter(configuration, ExecutableCondition.ANNOTATED_EXCEPTION_TYPES_NOT, condition.annotatedExceptionTypesNot) { key, value ->
val annotations = value.annotatedExceptionTypes.map { it.annotations.map { e -> e.annotationClass.java } }.flatten()
!compareElementTypes(key, annotations, configuration)
}
private inline fun <reified M : Member, reified R : MemberResolver<M, T>, T : Any> Sequence<M>.resolve(
configuration: MemberCondition.Configuration<T>
) = when (M::class) {
Method::class -> map { MethodResolver<T>(it as Method).apply(configuration) }
Constructor::class -> map { ConstructorResolver(it as Constructor<T>).apply(configuration) }
Field::class -> map { FieldResolver<T>(it as Field).apply(configuration) }
else -> error("Unsupported member type: $this")
}.toList() as List<R>
private fun <M : Member, R : MemberResolver<M, T>, T : Any> throwIfNotOptional(
condition: MemberCondition<M, R, T>,
configuration: MemberCondition.Configuration<T>
): List<R> {
fun splicingString(name: String) = "No $name found matching the condition for " +
"current class${if (configuration.superclass) " (Also tried for superclass)" else ""}.\n" +
buildConditionTable(condition, configuration) + "\n" +
"Suggestion: ${if (!configuration.superclass) "Members in superclass are not reflected in the current class, " +
"you can try adding superclass() in your condition and try again. "
else "Check if the conditions are correct and valid, and try again. "}"
val exceptionNote = "If you want to ignore this exception, adding optional() in your condition."
val message = when (condition) {
is MethodCondition -> splicingString(name = "method")
is ConstructorCondition -> splicingString(name = "constructor")
is FieldCondition -> splicingString(name = "field")
else -> error("Unsupported condition type: $condition")
}
return if (configuration.optional == MemberCondition.Configuration.Optional.NO) throw when (condition) {
is MethodCondition -> NoSuchMethodException("$message\n$exceptionNote\n$PRODUCT_DESCRIPTION")
is ConstructorCondition -> NoSuchMethodException("$message\n$exceptionNote\n$PRODUCT_DESCRIPTION")
is FieldCondition -> NoSuchFieldException("$message\n$exceptionNote\n$PRODUCT_DESCRIPTION")
else -> error("Unsupported condition type: $condition")
} else {
if (configuration.optional == MemberCondition.Configuration.Optional.NOTICE)
KavaRefRuntime.warn(message.trim())
emptyList()
}
}
private inline fun <reified M : Member, T : Any> MemberResolver<M, T>.apply(configuration: MemberCondition.Configuration<T>) =
apply { configuration.memberInstance?.let { if (this is InstanceAwareResolver) of(it) } }
private fun <T, R> Sequence<T>.filter(
configuration: MemberCondition.Configuration<*>,
name: String,
key: R?,
predicate: (key: R, value: T) -> Boolean
) = filter { condition ->
val predicateKey = if (key is Collection<*>)
key.takeIf { it.isNotEmpty() }
else key
predicateKey?.let {
val result = predicate(it, condition)
val sKey = VagueType.format(it)?.toStringIgnore()
val sValue = condition?.toStringIgnore()
if (configuration.optional != MemberCondition.Configuration.Optional.SILENT)
KavaRefRuntime.debug("[FILTER] [${if (result) "HIT" else "MISS"}] $name: $sKey [RESOLVED] $sValue")
result
} ?: true
}
private fun <T : Any> compareElementTypes(
conditionKey: Collection<Any>,
typesValue: List<Class<*>>,
configuration: MemberCondition.Configuration<T>
): Boolean {
// If size is different at first, return false.
if (conditionKey.size != typesValue.size) return false
val isMatched = conditionKey
.map { it.toTypeClass(configuration) }
.filterIndexed { index, type ->
val target = typesValue[index]
type == classOf<VagueType>() || target == type
}.size == typesValue.size
return isMatched
}
@JvmName("compareElementTypesMultiple")
private fun <T : Any> compareElementTypes(
conditionKey: Collection<Collection<Any>>,
typesValue: List<List<Class<*>>>,
configuration: MemberCondition.Configuration<T>
): Boolean {
// If size is different at first, return false.
if (conditionKey.size != typesValue.size) return false
val isMatched = conditionKey.filterIndexed { index, type ->
val target = typesValue[index]
compareElementTypes(type, target, configuration)
}.size == typesValue.size
return isMatched
}
private fun compareMatcherTypes(
conditionKey: Collection<TypeMatcher>,
typesValue: List<Type>
): Boolean {
// If size is different at first, return false.
if (conditionKey.size != typesValue.size) return false
val isMatched = conditionKey.filterIndexed { index, type ->
val target = typesValue[index]
type.matches(target)
}.size == typesValue.size
return isMatched
}
private fun <T : Any> buildConditionTable(
condition: MemberCondition<*, *, *>,
configuration: MemberCondition.Configuration<T>
) = runCatching {
fun displayWidth(str: String) = str.sumOf { if (it.code > 127L) 2L else 1L }.toInt()
fun padDisplay(str: String, targetWidth: Int): String {
val currentWidth = displayWidth(str)
val padding = targetWidth - currentWidth
return if (padding > 0) str + " ".repeat(padding) else str
}
val rows = condition.conditionStringMap.mapNotNull { (label, value) ->
val displayValue = when (value) {
null -> null
is Function<*> -> "(Runtime Condition)"
is Collection<*> -> if (value.isEmpty()) null else VagueType.format(value)
else -> VagueType.format(value)
// Remove the Kotlin reflection warning message.
}?.toStringIgnore()
displayValue?.let { label to it }
}
if (rows.isEmpty()) return configuration.declaringClass.toString()
val originalLabelWidth = rows.maxOf { displayWidth(it.first) }
val originalValueWidth = rows.maxOf { displayWidth(it.second) }
val headerText = configuration.declaringClass.toStringIgnore()
val headerWidth = displayWidth(headerText)
val contentWidth = originalLabelWidth + originalValueWidth + 3 // 3: " | "
// If header is wider, increase value column width.
val extraPadding = (headerWidth - contentWidth).coerceAtLeast(0)
val labelWidth = originalLabelWidth
val valueWidth = originalValueWidth + extraPadding
val border = "+-${"-".repeat(labelWidth)}-+-${"-".repeat(valueWidth)}-+"
val headerBorder = "+-${"-".repeat(labelWidth + valueWidth + 3)}-+"
val header = "| ${padDisplay(headerText, labelWidth + valueWidth + 3)} |"
val content = rows.joinToString("\n") { (label, value) ->
"| ${padDisplay(label, labelWidth)} | ${padDisplay(value, valueWidth)} |"
}
return listOf(headerBorder, header, border, content, border).joinToString("\n")
}.getOrDefault("${configuration.declaringClass.toStringIgnore()}\nFailed to build condition table.")
private val <T : Any> MemberCondition.Configuration<T>.currentProcessorResolver
get() = processorResolver ?: globalResolver
private val Member.annotations get() = when (this) {
is AnnotatedElement -> declaredAnnotations
else -> error("Unsupported member type: $this")
}
private fun Member.toGenericString() = when (this) {
is Method -> toGenericString()
is Constructor<*> -> toGenericString()
is Field -> toGenericString()
else -> error("Unsupported member type: $this")
}
private fun <T : Any> Any.toTypeClass(configuration: MemberCondition.Configuration<T>, noVague: String? = null): Class<*> {
fun Class<*>.parseVagueType() =
if (this == classOf<VagueType>())
noVague?.let { error("VagueType is not supported for \"$it\".") } ?: this
else this
return when (this) {
is Class<*> -> this
is KClass<*> -> this.java
is String -> if (configuration.optional == MemberCondition.Configuration.Optional.NO)
toClass(configuration.declaringClass.classLoader)
// If enabled optional mode, use the "Object.class" as the default return type when not found.
else toClassOrNull(configuration.declaringClass.classLoader) ?: classOf<Any>()
is VagueType -> javaClass
else -> error("Unsupported type: $this, supported types are Class, KClass, String and VagueType.")
}.parseVagueType()
}
private fun Any.toStringIgnore() = toString().replace(" (Kotlin reflection is not available)", "")
private inline fun runOrElse(block: () -> Boolean) = runCatching(block).getOrDefault(false)
}

View File

@@ -0,0 +1,209 @@
/*
* KavaRef - A modernizing Java Reflection with Kotlin.
* Copyright (C) 2019 HighCapable
* https://github.com/HighCapable/KavaRef
*
* Apache License Version 2.0
*
* 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
*
* https://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.
*
* This file is created by fankes on 2025/5/19.
*/
@file:Suppress("unused")
package com.highcapable.kavaref.runtime
import android.util.Log
import com.highcapable.kavaref.KavaRef
import com.highcapable.kavaref.extension.hasClass
import com.highcapable.kavaref.generated.KavarefCoreProperties
import org.slf4j.LoggerFactory
/**
* Runtime class for KavaRef logging.
*/
object KavaRefRuntime {
private const val TAG = KavarefCoreProperties.PROJECT_NAME
private val slf4jLogger by lazy { LoggerFactory.getLogger(TAG) }
private val isAndroidEnv by lazy {
javaClass.classLoader.hasClass("android.os.Build")
}
private var logger: Logger = DefaultLogger()
/**
* Log levels for KavaRef.
* @param levelName the name of the log level.
*/
enum class LogLevel(val levelName: String) {
/** DEBUG */
DEBUG("debug"),
/** INFO */
INFO("info"),
/** WARN */
WARN("warn"),
/** ERROR */
ERROR("error"),
/** OFF (Turn off logging) */
OFF("off")
}
/**
* Logger interface for KavaRef.
*
* You can implement this interface to create your own logger and set it to [KavaRef.setLogger].
*/
interface Logger {
/** Logger tag. */
val tag: String
/**
* Log a debug message.
* @param msg the message to log.
* @param throwable an optional throwable to log.
*/
fun debug(msg: Any?, throwable: Throwable? = null)
/**
* Log an info message.
* @param msg the message to log.
* @param throwable an optional throwable to log.
*/
fun info(msg: Any?, throwable: Throwable? = null)
/**
* Log a warning message.
* @param msg the message to log.
* @param throwable an optional throwable to log.
*/
fun warn(msg: Any?, throwable: Throwable? = null)
/**
* Log an error message.
* @param msg the message to log.
* @param throwable an optional throwable to log.
*/
fun error(msg: Any?, throwable: Throwable? = null)
}
/**
* Default logger implementation for KavaRef.
*
* This logger uses SLF4J for non-Android environments and Android Log for Android environments.
*/
private class DefaultLogger : Logger {
override val tag = TAG
override fun debug(msg: Any?, throwable: Throwable?) {
if (!isAndroidEnv)
slf4jLogger.debug(msg.toString(), throwable)
else Log.d(TAG, msg.toString(), throwable)
}
override fun info(msg: Any?, throwable: Throwable?) {
if (!isAndroidEnv)
slf4jLogger.info(msg.toString(), throwable)
else Log.i(TAG, msg.toString(), throwable)
}
override fun warn(msg: Any?, throwable: Throwable?) {
if (!isAndroidEnv)
slf4jLogger.warn(msg.toString(), throwable)
else Log.w(TAG, msg.toString(), throwable)
}
override fun error(msg: Any?, throwable: Throwable?) {
if (!isAndroidEnv)
slf4jLogger.error(msg.toString(), throwable)
else Log.e(TAG, msg.toString(), throwable)
}
}
/**
* Get or set the log level for KavaRef.
*
* Use [KavaRef.logLevel] to control it.
* @see KavaRef.logLevel
* @return [LogLevel]
*/
@get:JvmSynthetic
@set:JvmSynthetic
internal var logLevel = LogLevel.WARN
set(value) {
if (!isAndroidEnv)
// Enable level for SLF4J.
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", value.levelName)
field = value
}
/**
* Set the logger for KavaRef.
*
* Use [KavaRef.setLogger] to control it.
* @see KavaRef.setLogger
* @param logger the logger to be set.
*/
@JvmSynthetic
internal fun setLogger(logger: Logger) {
this.logger = logger
}
init {
// Initialize the log level to WARN if not set.
logLevel = logLevel
}
/**
* DEBUG
*/
@JvmSynthetic
internal fun debug(msg: Any?, throwable: Throwable? = null) {
if (shouldLog(LogLevel.DEBUG)) logger.debug(msg, throwable)
}
/**
* INFO
*/
@JvmSynthetic
internal fun info(msg: Any?, throwable: Throwable? = null) {
if (shouldLog(LogLevel.INFO)) logger.info(msg, throwable)
}
/**
* WARN
*/
@JvmSynthetic
internal fun warn(msg: Any?, throwable: Throwable? = null) {
if (shouldLog(LogLevel.WARN)) logger.warn(msg, throwable)
}
/**
* ERROR
*/
@JvmSynthetic
internal fun error(msg: Any?, throwable: Throwable? = null) {
if (shouldLog(LogLevel.ERROR)) logger.error(msg, throwable)
}
private fun shouldLog(level: LogLevel) = logLevel.ordinal <= level.ordinal
}