Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

Kotlin Reflection Library

License

NotificationsYou must be signed in to change notification settings

goatbytes/KFlect

Repository files navigation

KFlect
Style Guide-KotlinGradle DependencyMaven CentralAndroid | JVM

KFlect is a Kotlin library that provides dynamic access to class members. It enables you to inspect and manipulate classes at runtime, including private members, companion objects, and extension functions. This can be useful for testing, debugging, and advanced programming techniques.

Getting Started

Gradle

Add the following to yourbuild.gradle.kts in your project:

dependencies {  implementation("io.goatbytes:kflect:1.0.2")}

Example Usage

This guide demonstrates howkflect provides an efficient approach to interacting with classes dynamically. Using aPerson class as our example, we’ll walk through instance creation, modifying private members, invoking companion object functions, and even accessing top-level extension functions.

Here’s a simplePerson class with a private constructor, private fields, and a private function. Normally, these members would be inaccessible from the outside, but we can work with them flexibly throughkflect.

packageio.goatbytes.kflect.exampleclassPerson private constructor(valname:String,valage:Int,privatevalssn:String// Private property) {constructor(name:String, age:Int):this(name, age, generateSSN())fungetIntroduction():String="Hi, I'm$name and I'm$age years old."privatefungetPrivateInfo():String="SSN:$ssn"companionobject {privatefungenerateSSN():String {returnlistOf(3,2,4).joinToString("-") {        (1..it).joinToString("") { (1..9).random().toString() }      }    }  }}// Top-level extension functionsfun Person.greet()=println("Hello,$name!")privatefun Person.is21()= age>=21

Creating Instances

Withkflect, you can create an instance ofPerson even though the constructor is private:

kflect {val person="io.goatbytes.kflect.example.Person"("Jared",39)asPersonprintln(person.getIntroduction())// Output: "Hi, I'm Jared and I'm 39 years old."}

Accessing and Modifying Private Members

Sometimes, it’s necessary to read or modify private fields or call private methods.kflect allows this by letting us reach into the class and interact with its internal details:

kflect {val getPrivateInfo= person.function("getPrivateInfo")println(getPrivateInfo(person))// Output: "SSN: XXX-XX-XXXX"val generateSSN= person.function("generateSSN")  person["ssn"]= generateSSN()println(getPrivateInfo(person))// Updated SSN}

This method is particularly useful for testing, debugging, and working with data that would otherwise be restricted.


Companion Object Functions

We can also access companion object functions, including private ones. Here’s an example of calling the privategenerateSSN method:

kflect {val generateSSN= person.function("generateSSN")println("Generated SSN:${generateSSN()}")}

Calling Top-Level Extension Functions

You can even invoke top-level extension functions dynamically. Here’s how we usegreet and check theis21 function:

kflect {val greet= person.topLevelExtensionFunction(Person::class,"greet")  greet(person)// Output: "Hello, Jared!"val is21= person.topLevelExtensionFunction(Person::class,"is21")if (is21(person)==true) {println("${person.name} is old enough to attend the conference.")  }else {println("${person.name} isn't old enough for the conference yet.")  }}

Java Examples

Withkflect, you can simplify standard reflection tasks, such as invoking a method by name or accessing private fields in Java. This flexibility can save time during debugging or when working with restricted APIs.

Example: Accessing String Substring Method

val substringMethod="java.lang.String".method("substring",Int::class,Int::class)val result= substringMethod("Hello, World!",7,12)println(result)// Output: "World"

In this example, we’re callingsubstring on aString instance directly by the method name, which reduces the usual reflection boilerplate.

Example: Modifying Private Fields

val person="com.example.Person"("Jane Doe",25)asPersonperson["privateField"]="newValue"// Modify a private field directly

Here,kflect enables modification of private fields without the usualsetAccessible calls, making code more readable and concise.


Android Examples: Dynamic Interaction with Android Framework Classes

On Android,kflect becomes particularly valuable when working with the platform's reflection-heavy APIs, such as accessing hidden fields or methods in the Android SDK. Here’s an example of how to usekflect for tasks like obtaining the current activity:

Example: Accessing Current Activity

Android’s framework classes often require reflection for accessing certain hidden APIs or working with internal details. Usingkflect, you can dynamically obtain the currentActivity without direct references toActivityThread:

val currentActivity:Activity= kflect {  ("android.app.ActivityThread"("currentActivityThread")["mActivities"]asMap<*,*>)    .values.firstNotNullOf { record->when (record["paused"]==false) {true-> record["activity"]asActivity// return the active android.app.Activityelse->null      }    }}

This example is practical for use in debugging scenarios, dynamic feature delivery, and analytics libraries where obtaining the current activity context is essential.

Using Predicates for Reflection Filtering

Thepredicates package in KFlect enables you to filter and search class members—like methods, properties, fields, and constructors—using declarative conditions. This approach simplifies reflection by enablingselective access to class members based on your specific criteria.

KFlect’s predicates provide a highly readable,fluent interface for querying classes. Rather than manually iterating through members, predicates offer a way to dynamically filter the members you need, reducing boilerplate and increasing readability.


Available Predicates

KFlect’spredicates package offers a range of filters that target different kinds of class members. Each predicate can be chained to form complex criteria, providing you with fine-grained control over member selection.

Here’s a quick overview of the available predicate classes:

  • ConstructorPredicates: Filters constructors based on parameters, annotations, and accessibility.
  • ExecutablePredicates: General filters for executable members, like functions and methods.
  • FieldPredicates: Allows filtering fields based on type, visibility, and annotations.
  • KCallablePredicates: A generic set of filters for Kotlin callables, covering properties and functions.
  • KFunctionPredicates: Targets Kotlin-specific functions with conditions like return type and parameters.
  • KPropertyPredicates: Specific to properties, with filters for mutability, visibility, and initialization.
  • MemberPredicates: Broad member-level predicates to filter by name, annotations, and accessibility.
  • MethodPredicates: Focused on Java methods, filtering by return type, parameters, and annotations.

Example Usage: Filtering with Predicates

Using KFlect’s predicates, you can filter and select specific members of a class without looping manually. Below are some examples illustrating various use cases.

// Find functions in `Random` with a `Unit` return type and an `Int` parameterval functions=Random::class.filterFunctions {    returnType(Unit::class)and hasParameterType(Int::class)}// Filter public methods in `String` with one parameter and a return type of `String`val methods=String::class.java.filterMethods {    hasParameterCount(1)and returnType(String::class.java)and isPublic()}// Locate a property in `StringBuilder` with an `Int` return type and the name "length"val property=StringBuilder::class.findProperty {    returnType(Int::class)and name("length")}// Find a method in `StringBuilder` named "length" with an `Int` return typeval method=StringBuilder::class.java.findMethod {    name("length")and returnType(Int::class.java)}

In these examples,filterFunctions,filterMethods,findProperty, andfindMethod leverage predicates to locate members matching specific conditions.

Predicate Chaining

KFlect’s predicates can be chained usingand,or, andnot, making it easy to build complex conditions. For instance:

val functionsWithConditions=MyClass::class.filterFunctions {  returnType(Unit::class)and (isPublic()or hasAnnotation<Deprecated>())}

This query retrieves allUnit-returning functions inString that are eitherpublic or annotated with@Deprecated.

Lazy Initialization

KFlect includesLazyKFlect andSynchronizedLazyKFlect for situations whereon-demand initialization of reflection data is preferred. These classes are particularly useful for performance-sensitive applications or cases where reflection data might not be required immediately.


LazyKFlect

LazyKFlect enables lazy initialization of reflection-related objects, ensuring that they’re only created when accessed for the first time. This approach minimizes the initial memory footprint and computation cost, as resources are allocated only when necessary.

val lazyReflection byLazyKFlect {"io.goatbytes.kflect.example.Person"("Alice",28)asPerson }

SynchronizedLazyKFlect

Formultithreaded environments,SynchronizedLazyKFlect provides thread-safe lazy initialization by ensuring that only one thread can initialize the reflection data at a time.

val synchronizedLazyReflection bySynchronizedLazyKFlect {"io.goatbytes.kflect.example.Person"("Bob",35)asPerson }

Packages

src└── main    └── kotlin        └── io            └── goatbytes                └── kflect                    ├── cache        // Caching mechanism for reflection data                    ├── dsl          // DSL for simplified reflection queries                    ├── exceptions   // Custom exceptions for reflection handling                    ├── ext          // Extension functions for reflection utilities                    ├── lazy         // Lazy initialization utilities for reflection                    ├── misc         // Miscellaneous helpers, like unsafe operations                    ├── os           // OS-specific utilities                    ├── predicates   // Predicates for filtering reflection data                    └── traverser    // Traversal utilities for classes and functions                        └── ext      // Extensions supporting traversal operations

Contributing

Contributions are welcome! Please read ourcontributing guide and submit pullrequests to our repository.

License

This project is licensed under the Apache 2.0 License — see theLICENSE file for details.

ℹ️ About GoatBytes.IO

GoatBytesLogo

GitHubTwitterLinkedInInstagram

AtGoatBytes.IO, our mission is to develop secure software solutions that empower businesses totransform the world. With a focus on innovation and excellence, we strive to deliver cutting-edgeproducts that meet the evolving needs of businesses across various industries.


[8]ページ先頭

©2009-2025 Movatter.jp