简体   繁体   中英

Access Kotlin Delegate Type without an Instance

I have read Access property delegate in Kotlin which is about accessing a delegate from an instance. One can use KProperty::getDelegate since Kotlin 1.1, however this will return the instance of the delegate and therefore needs an instance of the class first.

Now I want to get the type of the delegate without having an instance of the class. Consider a library with a custom delegate type CustomDelegate that want's to get all properties of a class that are delegated to an instance of CustomDelegate :

class Example
{
    var nonDelegatedProperty = "I don't care about this property"
    var delegatedProperty1 by lazy { "I don't care about this too" }
    var delegatedProperty2 by CustomDelegate("I care about this one")
}

How can I, given I have KClass<Example> , but not an instance of Example , get all properties delegated to CustomDelegate ?

How can I, given I have KClass<Example>, but not an instance of Example, get all properties delegated to CustomDelegate?

You can do it in two ways depending on your needs.

First of all, you have to include the kotlin-reflect dependency in your build.gradle file:

compile "org.jetbrains.kotlin:kotlin-reflect:1.1.51"

In my opinion, you should use the first solution if you can, because it's the most clear and optimized one. The second solution instead, can handle one case that the first solution can't.

First

You can loop an the declared properties and check if the type of the property or the type of the delegate is CustomDelegate .

// Loop on the properties of this class.
Example::class.declaredMemberProperties.filter { property ->
    // If the type of field is CustomDelegate or the delegate is an instance of CustomDelegate,
    // it will return true.
    CustomDelegate::class.java == property.javaField?.type
}

There's only one problem with this solution, you will get also the fields with type CustomDelegate , so, given this example:

class Example {
    var nonDelegatedProperty = "I don't care about this property"
    val delegatedProperty1 by lazy { "I don't care about this too" }
    val delegatedProperty2 by CustomDelegate("I care about this one")
    val customDelegate = CustomDelegate("jdo")
}

You will get delegatedProperty2 and customDelegate . If you want to get only delegatedProperty2 , I found an horrible solution that you can use if you need to manage this case.

Second

If you check the source code of KPropertyImpl , you can see how a delegation is implemented. So, you can do something like this:

// Loop on the properties of this class.
Example::class.declaredMemberProperties.filter { property ->
    // You must check in all superclasses till you find the right method.
    property::class.allSuperclasses.find {
        val computeField = try {
            // Find the protected method "computeDelegateField".
            it.declaredFunctions.find { it.name == "computeDelegateField" } ?: return@find false
        } catch (t: Throwable) {
            // Catch KotlinReflectionInternalError.
            return@find false
        }

        // Get the delegate or null if the delegate is not present.
        val delegateField = computeField.call(property) as? Field
        // If the delegate was null or the type is different from CustomDelegate, it will return false.
        CustomDelegate::class.java == delegateField?.type
    } != null
}

In this case, you will get only delegatedProperty2 as result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM