import{_ as c,r as t,o as i,c as p,b as s,d as e,e as n,w as a,a as d}from"./app-mh6GuRj9.js";const r={},u=s("h1",{id:"migration-to-kavaref",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#migration-to-kavaref","aria-hidden":"true"},"#"),e(" Migration to KavaRef")],-1),y={href:"https://github.com/HighCapable/YukiReflection",target:"_blank",rel:"noopener noreferrer"},v={href:"https://github.com/HighCapable/YukiHookAPI",target:"_blank",rel:"noopener noreferrer"},A=s("code",null,"KavaRef",-1),m=d(`

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:

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!")
`,32),h=s("h2",{id:"new-to-kavaref",tabindex:"-1"},[s("a",{class:"header-anchor",href:"#new-to-kavaref","aria-hidden":"true"},"#"),e(" New to KavaRef")],-1),D=s("p",null,[e("If you haven't used "),s("code",null,"YukiReflection"),e(" or "),s("code",null,"YukiHookAPI"),e(", it doesn't matter, you can refer to the following content to get started quickly.")],-1),C={class:"custom-container tip"},f=s("p",{class:"custom-container-title"},"What to Do Next",-1),B=s("p",null,[e("Get started using "),s("code",null,"KavaRef"),e(" now!")],-1);function g(b,F){const l=t("ExternalLinkIcon"),o=t("RouterLink");return i(),p("div",null,[u,s("p",null,[e("If you are used to using the reflection API in "),s("a",y,[e("YukiReflection"),n(l)]),e(" or "),s("a",v,[e("YukiHookAPI"),n(l)]),e(", you can refer to the following to migrate to "),A,e(".")]),m,s("p",null,[e("For more information, please refer to the "),n(o,{to:"/en/library/kavaref-core.html#exception-handling"},{default:a(()=>[e("Exception Handling")]),_:1}),e(" section in "),n(o,{to:"/en/library/kavaref-core.html"},{default:a(()=>[e("kavaref-core")]),_:1}),e(".")]),h,D,s("div",C,[f,s("p",null,[e("For more information, please continue reading "),n(o,{to:"/en/library/kavaref-core.html"},{default:a(()=>[e("kavaref-core")]),_:1}),e(" and "),n(o,{to:"/en/library/kavaref-extension.html"},{default:a(()=>[e("kavaref-extension")]),_:1}),e(".")]),B])])}const R=c(r,[["render",g],["__file","migration.html.vue"]]);export{R as default};