web-dev-qa-db-fra.com

Accès à la fonction d'extension Kotlin Java

Je voudrais accéder à Java champ privé lors de l'utilisation de Kotlin fonction d'extension.

Supposons que j'ai une classe JavaABC. ABC n'a qu'un seul champ privé mPrivateField. Je voudrais écrire une fonction d'extension dans Kotlin qui utilise ce champ pour une raison quelconque.

public class ABC {
    private int mPrivateField;

}

la fonction Kotlin serait:

private fun ABC.testExtFunc() {
    val canIAccess = this.mPrivateField;
}

l'erreur que je reçois est:

Cannot access 'mPrivateField': It is private in 'ABC'

Une façon de se déplacer cette limitation?

Tout d'abord, vous devez obtenir un Field et l'activer peut être accessible dans Kotlin, par exemple:

val field = ABC::class.Java.getDeclaredField("mPrivateField")

field.isAccessible = true

Ensuite, vous pouvez lire la valeur du champ comme Int par Field # getInt à partir de l'instance de la classe déclarante, par exemple:

val it: ABC = TODO()

val value = field.getInt(it)

Enfin, votre méthode d'extension est la suivante:

private inline fun ABC.testExtFunc():Int {
    return javaClass.getDeclaredField("mPrivateField").let {
        it.isAccessible = true
        val value = it.getInt(this)
        //todo
        return@let value;
    }
}
22
holi-java

Ce n'est pas possible par conception. Les fonctions d'extension se résolvent essentiellement en fonctions statiques avec le récepteur comme premier paramètre. Ainsi, une fonction d'extension

fun String.foo() {
  println(this)
}

compile quelque chose comme:

public static void foo(String $receiver) {
  System.out.println($receiver);
}

Maintenant, il est clair que vous ne pouvez pas accéder au membre privé de $receiver, puisqu'ils sont, eh bien, privés.

Si vous vraiment voulez accéder à ce membre, vous pouvez le faire en utilisant la réflexion, mais vous perdrez toutes les garanties.

8
nhaarman

Tout comme nhaarman m'a suggéré d'utiliser réflexion pour accéder au champ en question. Plus précisément, j'ai créé un getter qui utilise la réflexion en interne sur la classe mentionnée (c'est-à-dire ABC)

Malheureusement, l'accès aux champs privés dans la fonction d'extension Kotlin n'est pas possible à partir du juillet 2017

fun ABC.testExtFunc() {
    val canIAccess = this.getmPrivateField()
}

fun ABC.getmPrivateField() : Int {
    val field = this.javaClass.declaredFields
            .toList().filter { it.name == "mPrivateField" }.first()
    field.isAccessible = true
    val value = field.get(this)
    return value as Int
}

Étendre la réponse de holi-Java avec un type générique:

  1. Créer une extension
fun<T: Any> T.accessField(fieldName: String): Any? {
    return javaClass.getDeclaredField(fieldName).let { field ->
        field.isAccessible = true
        return@let field.get(this)
    }
}

  1. Accéder au domaine privé
val field = <your_object_instance_with_private_field>
                .accessField("<field_name>")
                    as <object_type_of_field_name>

Exemple:

class MyClass {

    private lateinit var mObject: MyObject

}

val privateField = MyClass()
                .accessField("mObject")
                    as MyObject

1
Victor R. Oliveira