One day, if you want to write a framework to show Kotlin’s reflection, the framework needs to take a method of a type and call it.

To simplify things, let’s go straight to the String method and write the following code (cheerfully) :


     
  1.    String::class.memberFunctions

  2.            .first{ it.name == "toInt" && it.parameters.first().type.jvmErasure == Int::class}

  3.            .call("7f12abcd", 16).let(::println)

Copy the code

What is this for? We want to call the following method to convert the string to an Int:


     
  1. public inline fun String.toInt(radix: Int): Int = java.lang.Integer.parseInt(this, checkRadix(radix))

Copy the code

Equivalent to the following call:


     
  1.    "7f12abcd".toInt(16).let(::println)

Copy the code

Unfortunately, however, this code runs with an exception:


     
  1. Exception in thread "main" kotlin.reflect.jvm.internal.KotlinReflectionInternalError:

  2. Reflection on built-in Kotlin types is not yet fully supported.

  3. No metadata found for public open val length:

  4. kotlin.Int defined in kotlin.String[DeserializedPropertyDescriptor@1018bde2]

Copy the code

Ok, great. Looks like it’s not my code because the error message says: Kotlin reflection is not fully supported for built-in types!!

What the hell! Can you still play happily? It is enough to introduce a 2.5m reflection pack (Tencent map’s vector SDK is only a little more than 1M), and the result is not playable?

A little Google reflective access to built-in classes and members showed I wasn’t alone

All right, let’s see what the hell this is, okay

The location of the error is a String property called length. Ok, in the string. kt file, we can only see the following code:


     
  1. public class String : Comparable<String>, CharSequence {

  2. .

  3.    public override val length: Int

  4. .

  5. }

Copy the code

Is this class not implemented? String is not an abstract class. Why is there nothing after length?

Don’t panic. This thing is just a shell. Kotlin’s compiler maps the String::length property to the Java string.length () method, in other words, it doesn’t need to be implemented at all, more like a smokescreen.

Because of this, Kotlin’s String::length does not actually exist for the Jvm, so there is no Jvm signature, so the previous reflection code reported an error.

Since the current version of Kotlin’s reflection library (1.1.4-2) doesn’t seem to have much optimization either, Kotlin will first calculate all the members of the class and then filter them, whether you want to get methods, attributes, or extended attributes and methods. Let’s take a look at two random examples:


     
  1. val KClass<*>.memberFunctions: Collection<KFunction<*>>

  2.    get() = (this as KClassImpl).data().allNonStaticMembers.filter { it.isNotExtension && it is KFunction<*> } as Collection<KFunction<*>>

  3. val KClass<*>.memberExtensionFunctions: Collection<KFunction<*>>

  4.    get() = (this as KClassImpl).data().allNonStaticMembers.filter { it.isExtension && it is KFunction<*> } as Collection<KFunction<*>>

Copy the code

The problem with this is that as long as the class has a mapping problem to a Java class or method, its reflection is basically useless. In other words, not just strings, but things like maps, and even enUms.

The Number family does not support type mapping, so it is only a matter of time before other types are supported.

Wow, what do you do with a problem like that?

Very simple, encountered such a mapping problem, usually means that the thing is Java itself, Java reflection is good!

As you can see from forum posts, Kotlin’s reflection isn’t doing much optimization right now and is slower to use than its Java equivalent, so think twice about using it.

I have to say that Kotlin’s pit is basically caused by compatibility with Java, such as the type mapping problems mentioned in the previous several articles, data class problems, I believe that in the later version of Kotlin, these problems will not be a problem ~~