Migration to KavaRef
If you are used to using the reflection API in YukiReflection or YukiHookAPI, you can refer to the following to migrate to KavaRef
.
Notice
For YukiHookAPI
, you need to continue using its Hook API, and KavaRef
only includes Java reflection-related APIs.
Basic Functions
The design concept of KavaRef
is similar to YukiReflection
, but not exactly the same. The following lists the differences between YukiReflection
and KavaRef
in basic reflection functions, which you can manually migrate based on.
For example, we have the following Java class.
The following example
public class MyClass {
private void myMethod(String content) {
System.out.println("Hello " + content + "!");
}
}
Here is a comparison of KavaRef
with YukiReflection
using examples.
The following example
KavaRef
// Assume that's your MyClass instance.
val myClass: MyClass
// Call and execute using KavaRef.
MyClass::class.resolve().firstMethod {
name = "myMethod"
parameters(String::class)
}.of(myClass).invoke("Hello, KavaRef!")
// Direct reference to instance.
myClass.asResolver().firstMethod {
name = "myMethod"
parameters(String::class)
}.invoke("Hello, KavaRef!")
YukiReflection
// Assume that's your MyClass instance.
val myClass: MyClass
// Call and execute using YukiReflection.
MyClass::class.java.method {
name = "myMethod"
param(StringClass)
}.get(myClass).call("Hello, YukiReflection!")
// Direct reference to instance.
myClass.current().method {
name = "myMethod"
param(StringClass)
}.call("Hello, YukiReflection!")
KavaRef
starts reflection at any time; you need to use resolve()
to create a reflection scope. You no longer directly extend the related method
and constructor
methods to avoid polluting their scope.
KavaRef
provides the asResolver()
method to directly reference the reflection scope of the instance object, avoiding pollution caused by the creation of uncontrollable instance objects by the current()
method in YukiReflection
.
KavaRef
abandons the "Finder" design concept and uses the "Filter" design concept to obtain reflection results. "Find" is no longer finding, but "filtering".
KavaRef
canceled the design scheme defined in YukiReflection
for determining whether the Member
obtained in the resulting instance is multiple or single, and directly returns the entire List<MemberResolver>
. The example you see above uses firstMethod
to get the first matching MethodResolver
. If you need to get all matches, you can change to method
.
The conditional method name in MethodCondition
of KavaRef
has been modified from abbreviations such as param
used previously in YukiReflection
to parameters
to better align with the naming conventions of the Java reflection API.
KavaRef
no longer provides the param(...).order()
function in conditions, because this function itself is unstable. KavaRef
now uses an iterator for filtering, and the bytecode will no longer be in order, nor should bytecode be filtered by order. You can use firstMethod
, firstField
, or lastMethod
, lastField
, etc. to get the first or last matching result.
KavaRef
renames the get(instance)
method to of(instance)
because get(...)
may be confused with the get(...)
usage of Field
and lacks semantic clarity. At the same time, get(instance)
no longer gets the MethodFinder.Result.Instance
instance from something like MethodFinder.Result
, but uses of(instance)
to consistently operate and set the instance object to MemberResolver
.
Methods such as string()
, int()
, etc. in MethodFinder.Result.Instance
have been removed in KavaRef
. You can directly use get<String>()
, get<Int>()
, invoke<String>(...)
, invoke<Int>(...)
, etc. to get or call the corresponding type results.
Pay Attention
If you are looking for (filtering) Field
, you need to note that there may be semantic conflicts between KavaRef
and YukiReflection
in the acquisition method of Field
. Please pay special attention when migrating this part.
For example, get the static field of content
in MyClass
, in YukiReflection
, you would do this.
The following example
MyClass::class.java
.field { name = "content" } // Return FieldFinder.Result
.get() // Cannot be omitted, return FieldFinder.Result.Instance
.string() // value
In KavaRef
you need to do this.
The following example
MyClass::class.resolve()
.firstField { name = "content" } // Return FieldResolver<MyClass>
.get<String>() // value
As mentioned above, get(...)
is used to get the FieldFinder.Result.Instance
object in YukiReflection
, not the value. To get the value and process it as a specified type, you need to call string()
or cast<String>()
, and in KavaRef
, you use get<T>()
directly in MemberResolver
to get the value of the specified type. The usage of get(...)
of KavaRef
for get(...)
to of(...)
.
So the complete writing of the above example in KavaRef
should be.
The following example
// Since the call is a static instance, "of(null)" can be omitted.
MyClass::class.resolve()
.firstField { name = "content" } // It's already a call chain object FieldResolver<MyClass>
.of(null) // Can be omitted and return to the call chain object FieldResolver<MyClass>
.get<String>() // value
KavaRef
no longer provides call
methods for Method
, and is now merged uniformly into invoke
(with generic parameters). At the same time, KavaRef
defines the newInstance
method of Constructor
as create
(with generic parameters).
You may have noticed that the condition superClass()
is gone, it is still there, in KavaRef
it has been renamed to superclass()
, docking with the standard Java reflection API.
At the same time, KavaRef
extends KClass
, and you no longer need to use Some::class.java
to declare an instance of Class
in most scenarios.
Another design idea of KavaRef
is type safety. As long as you use KClass<T>
and Class<T>
that declare the generic type, it will be checked and converted to the corresponding type when of(instance)
and create(...)
, and type checking will be completed during coding to avoid runtime errors.
The following example
// Assume that's your MyClass instance.
val myClass: MyClass
// Using KavaRef to call and execute.
MyClass::class.resolve()
.firstMethod {
name = "myMethod"
parameters(String::class)
}
// Only instances of type MyClass can be passed in.
.of(myClass)
.invoke("Hello, KavaRef!")
Other Functions
KavaRef
and YukiReflection
are not much different in other functions and extended functions. KavaRef
separates these functions into a separate module.
The following functionality is provided in YukiReflection
but is not implemented and no longer provided in KavaRef
:
Preset reflection type constant classes, such as
StringClass
,IntType
, etc- You can use Kotlin class references such as
String::class
,Int::class
, etc. to instead it. For primitive types and wrapper classes,IntType
is equivalent toInt::class
, andIntClass
is equivalent toJInteger::class
- You can use Kotlin class references such as
DexClassFinder
function- Due to its design flaws and possible performance issues when used on Android platforms, it is no longer available for now
RemedyPlan
andmethod { ... } .remedys { ... }
functions- Due to possible black box problems, maintenance is relatively difficult. If you need to use similar functions, please implement them manually and will no longer be provided
ClassLoader.listOfClasses()
function- Due to the complex and unstable implementation solutions of each platform, it will no longer be provided
ClassLoader.searchClass()
function- Due to performance issues and design time is limited to Android platform, it is relatively difficult to maintain filter conditions and is no longer provided
Class.hasExtends
,Class.extends
,Class.implements
functions- You can replace them with
A::class isSubclassOf B::class
- You can replace them with
Class.toJavaPrimitiveType()
function- There is conceptual confusion in functional design and will no longer be provided
"com.some.clazz".hasClass(loader)
function- You can use
loader.hasClass("com.some.clazz")
to instead it
- You can use
Class.hasField
,Class.hasMethod
,Class.hasConstructor
functions- Due to design defects, no longer provided
Class.hasModifiers(...)
,Member.hasModifiers(...)
functions- You can replace them directly with extension methods such as
Class.isPublic
,Member.isPublic
- You can replace them directly with extension methods such as
Class.generic()
,GenericClass
functions- If you just want to get generic parameters of the superclass, you can use
Class.genericSuperclassTypeArguments()
. Due to design defects, no longer provided
- If you just want to get generic parameters of the superclass, you can use
Any.current()
,CurrentClass
functions- You can use
Any.asResolver()
to instead it
- You can use
Class.buildOf(...)
function- You can use
Class.createInstance(...)
to instead it
- You can use
Class.allMethods()
,Class.allFields()
,Class.allConstructors()
functions- Due to its pollution scope, no longer provided
YLog
log functionKavaRef
no longer takes over the logs, you can use the corresponding platform implementation method and no longer provided
Exception Handling
KavaRef
is completely different from YukiReflection
in exception handling. The exception logic of KavaRef
will remain transparent by default. It no longer actively intercepts exceptions and prints error logs or even provides onNoSuchMethod
listener. When no valid members are filtered, KavaRef
will throw an exception directly unless you explicitly declare the condition as optional (consistent with YukiReflection
logic).
The following example
// Assume that's your MyClass instance.
val myClass: MyClass
// Using KavaRef to call and execute.
MyClass::class.resolve()
.optional() // Declare as optional, do not throw exceptions.
// Use firstMethodOrNull instead of firstMethod,
// because the NoSuchElementException of Kotlin itself will be thrown.
.firstMethodOrNull {
name = "doNonExistentMethod" // Assume that this method does not exist.
parameters(String::class)
}?.of(myClass)?.invoke("Hello, KavaRef!")
For more information, please refer to the Exception Handling section in kavaref-core.
New to KavaRef
If you haven't used YukiReflection
or YukiHookAPI
, it doesn't matter, you can refer to the following content to get started quickly.
What to Do Next
For more information, please continue reading kavaref-core and kavaref-extension.
Get started using KavaRef
now!