Use descriptors for reflection on extension properties
This commit is contained in:
+22
-5
@@ -3,10 +3,13 @@ import kotlin.test.assertEquals
|
||||
|
||||
fun check(expected: String, p: KExtensionProperty<*, *>) {
|
||||
var s = p.toString()
|
||||
|
||||
// Strip "val" or "var"
|
||||
assert(s.startsWith("val ") || s.startsWith("var ")) { "Fail val/var: $s" }
|
||||
s = s.substring(4)
|
||||
|
||||
// Strip property name, leave only receiver class
|
||||
s = s.substring(0, s.lastIndexOf('.'))
|
||||
s = s.substringBeforeLast('.')
|
||||
|
||||
assertEquals(expected, s)
|
||||
}
|
||||
@@ -34,7 +37,14 @@ val Array<Any>.a2: Any get() = this
|
||||
val Array<Array<String>>.a3: Any get() = this
|
||||
val Array<BooleanArray>.a4: Any get() = this
|
||||
|
||||
val Any?.n1: Any get() = Any()
|
||||
val Int?.n2: Any get() = Any()
|
||||
val Array<Any>?.n3: Any get() = Any()
|
||||
val Array<Any?>.n4: Any get() = Any()
|
||||
val Array<Any?>?.n5: Any get() = Any()
|
||||
|
||||
val Map<String, Runnable>.m: Any get() = this
|
||||
val List<MutableSet<Array<CharSequence>>>.l: Any get() = this
|
||||
|
||||
fun box(): String {
|
||||
check("kotlin.Boolean", Boolean::x)
|
||||
@@ -55,12 +65,19 @@ fun box(): String {
|
||||
check("kotlin.LongArray", LongArray::x)
|
||||
check("kotlin.DoubleArray", DoubleArray::x)
|
||||
|
||||
check("kotlin.Array<java.lang.Integer>", Array<Int>::a1)
|
||||
check("kotlin.Array<java.lang.Object>", Array<Any>::a2)
|
||||
check("kotlin.Array<kotlin.Array<java.lang.String>>", Array<Array<String>>::a3)
|
||||
check("kotlin.Any?", Any?::n1)
|
||||
check("kotlin.Int?", Int?::n2)
|
||||
check("kotlin.Array<kotlin.Any>?", Array<Any>?::n3)
|
||||
check("kotlin.Array<kotlin.Any?>", Array<Any?>::n4)
|
||||
check("kotlin.Array<kotlin.Any?>?", Array<Any?>?::n5)
|
||||
|
||||
check("kotlin.Array<kotlin.Int>", Array<Int>::a1)
|
||||
check("kotlin.Array<kotlin.Any>", Array<Any>::a2)
|
||||
check("kotlin.Array<kotlin.Array<kotlin.String>>", Array<Array<String>>::a3)
|
||||
check("kotlin.Array<kotlin.BooleanArray>", Array<BooleanArray>::a4)
|
||||
|
||||
check("java.util.Map", Map<String, Runnable>::m)
|
||||
check("kotlin.Map<kotlin.String, java.lang.Runnable>", Map<String, Runnable>::m)
|
||||
check("kotlin.List<kotlin.MutableSet<kotlin.Array<kotlin.CharSequence>>>", List<MutableSet<Array<CharSequence>>>::l)
|
||||
|
||||
return "OK"
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ fun assertToString(s: String, x: Any) {
|
||||
fun box(): String {
|
||||
assertToString("val top", ::top)
|
||||
assertToString("var top2", ::top2)
|
||||
assertToString("val java.lang.String.ext", String::ext)
|
||||
assertToString("var kotlin.IntRange.ext2", IntRange::ext2)
|
||||
assertToString("val kotlin.String.ext", String::ext)
|
||||
assertToString("var kotlin.IntRange?.ext2", IntRange::ext2)
|
||||
assertToString("val test.A.mem", A::mem)
|
||||
assertToString("var test.B.mem", B::mem)
|
||||
return "OK"
|
||||
|
||||
+9
@@ -56,5 +56,14 @@ public val Class<*>.classId: ClassId
|
||||
else -> getDeclaringClass()?.classId?.createNestedClassId(Name.identifier(getSimpleName())) ?: ClassId.topLevel(FqName(getName()))
|
||||
}
|
||||
|
||||
public val Class<*>.desc: String
|
||||
get() {
|
||||
if (this == Void.TYPE) return "V"
|
||||
// This is a clever exploitation of a format returned by Class.getName(): for arrays, it's almost an internal name,
|
||||
// but with '.' instead of '/'
|
||||
// TODO: ensure there are tests on arrays of nested classes, multi-dimensional arrays, etc.
|
||||
return createArrayType().getName().substring(1).replace('.', '/')
|
||||
}
|
||||
|
||||
public fun Class<*>.createArrayType(): Class<*> =
|
||||
Array.newInstance(this, 0).javaClass
|
||||
|
||||
+5
-14
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.load.kotlin.reflect
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.desc
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.isEnumClassOrSpecializedEnumEntryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
@@ -209,10 +210,10 @@ private object SignatureSerializer {
|
||||
val sb = StringBuilder()
|
||||
sb.append("(")
|
||||
for (parameterType in method.getParameterTypes()) {
|
||||
sb.append(typeDesc(parameterType))
|
||||
sb.append(parameterType.desc)
|
||||
}
|
||||
sb.append(")")
|
||||
sb.append(typeDesc(method.getReturnType()))
|
||||
sb.append(method.getReturnType().desc)
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
@@ -220,23 +221,13 @@ private object SignatureSerializer {
|
||||
val sb = StringBuilder()
|
||||
sb.append("(")
|
||||
for (parameterType in constructor.getParameterTypes()) {
|
||||
sb.append(typeDesc(parameterType))
|
||||
sb.append(parameterType.desc)
|
||||
}
|
||||
sb.append(")V")
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun fieldDesc(field: Field): String {
|
||||
return typeDesc(field.getType())
|
||||
}
|
||||
|
||||
suppress("UNCHECKED_CAST")
|
||||
fun typeDesc(clazz: Class<*>): String {
|
||||
if (clazz == Void.TYPE) return "V";
|
||||
// This is a clever exploitation of a format returned by Class.getName(): for arrays, it's almost an internal name,
|
||||
// but with '.' instead of '/'
|
||||
// TODO: ensure there are tests on arrays of nested classes, multi-dimensional arrays, etc.
|
||||
val arrayClass = java.lang.reflect.Array.newInstance(clazz as Class<Any>, 0).javaClass
|
||||
return arrayClass.getName().substring(1).replace('.', '/')
|
||||
return field.getType().desc
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.desc
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
@@ -26,12 +27,25 @@ abstract class KCallableContainerImpl {
|
||||
|
||||
abstract val scope: JetScope
|
||||
|
||||
protected fun findPropertyDescriptor(name: String): () -> PropertyDescriptor = {
|
||||
val properties = scope.getProperties(Name.identifier(name))
|
||||
protected fun findPropertyDescriptor(name: String, receiverParameterClass: Class<*>? = null): () -> PropertyDescriptor = {
|
||||
val receiverDesc = receiverParameterClass?.desc
|
||||
|
||||
val properties = scope
|
||||
.getProperties(Name.identifier(name))
|
||||
.filter { descriptor ->
|
||||
descriptor is PropertyDescriptor &&
|
||||
descriptor.getName().asString() == name &&
|
||||
with(descriptor.getExtensionReceiverParameter()) {
|
||||
(this == null && receiverDesc == null) ||
|
||||
(this != null && RuntimeTypeMapper.mapTypeToJvmDesc(getType()) == receiverDesc)
|
||||
}
|
||||
}
|
||||
|
||||
if (properties.size() != 1) {
|
||||
val debugText = if (receiverParameterClass == null) name else "${receiverParameterClass.getSimpleName()}.$name"
|
||||
throw KotlinReflectionInternalError(
|
||||
if (properties.isEmpty()) "Property $name not resolved in $this"
|
||||
else "${properties.size()} properties with name $name resolved in $this"
|
||||
if (properties.isEmpty()) "Property '$debugText' not resolved in $this"
|
||||
else "${properties.size()} properties '$debugText' resolved in $this"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.findClassAcrossModuleDependencies
|
||||
import kotlin.jvm.internal.KotlinClass
|
||||
@@ -38,7 +37,7 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
|
||||
val descriptor by ReflectProperties.lazySoft {(): ClassDescriptor ->
|
||||
val moduleData = jClass.getOrCreateModule()
|
||||
val classId = jClass.classId
|
||||
val classId = RuntimeTypeMapper.mapJvmClassToKotlinClassId(jClass)
|
||||
|
||||
val descriptor =
|
||||
if (classId.isLocal()) moduleData.localClassResolver.resolveLocalClass(classId)
|
||||
|
||||
@@ -32,21 +32,19 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP
|
||||
override val scope: JetScope get() = descriptor.getMemberScope()
|
||||
|
||||
fun topLevelVariable(name: String): KTopLevelVariable<*> {
|
||||
val descriptor = findPropertyDescriptor(name)
|
||||
return KTopLevelVariableImpl(this, descriptor)
|
||||
return KTopLevelVariableImpl(this, findPropertyDescriptor(name))
|
||||
}
|
||||
|
||||
fun mutableTopLevelVariable(name: String): KMutableTopLevelVariable<*> {
|
||||
val descriptor = findPropertyDescriptor(name)
|
||||
return KMutableTopLevelVariableImpl(this, descriptor)
|
||||
return KMutableTopLevelVariableImpl(this, findPropertyDescriptor(name))
|
||||
}
|
||||
|
||||
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KTopLevelExtensionProperty<T, *> {
|
||||
return KTopLevelExtensionPropertyImpl(name, this, receiver)
|
||||
return KTopLevelExtensionPropertyImpl(this, findPropertyDescriptor(name, receiver))
|
||||
}
|
||||
|
||||
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableTopLevelExtensionProperty<T, *> {
|
||||
return KMutableTopLevelExtensionPropertyImpl(name, this, receiver)
|
||||
return KMutableTopLevelExtensionPropertyImpl(this, findPropertyDescriptor(name, receiver))
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
|
||||
+19
-64
@@ -16,27 +16,24 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import java.lang.reflect.*
|
||||
import kotlin.reflect.*
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableTopLevelExtensionProperty
|
||||
import kotlin.reflect.KTopLevelExtensionProperty
|
||||
|
||||
open class KTopLevelExtensionPropertyImpl<T, out R>(
|
||||
override val name: String,
|
||||
protected val owner: KPackageImpl,
|
||||
protected val receiverClass: Class<T>
|
||||
) : KTopLevelExtensionProperty<T, R>, KPropertyImpl<R> {
|
||||
override val field: Field? get() = null
|
||||
override val container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : DescriptorBasedProperty(computeDescriptor), KTopLevelExtensionProperty<T, R>, KPropertyImpl<R> {
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
// TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields
|
||||
override val getter: Method = try {
|
||||
owner.jClass.getMethod(getterName(name), receiverClass)
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
throw NoSuchPropertyException(e)
|
||||
}
|
||||
override val getter: Method get() = super<DescriptorBasedProperty>.getter!!
|
||||
|
||||
override fun get(receiver: T): R {
|
||||
try {
|
||||
return getter(null, receiver) as R
|
||||
[suppress("UNCHECKED_CAST")]
|
||||
return getter.invoke(null, receiver) as R
|
||||
}
|
||||
catch (e: IllegalAccessException) {
|
||||
throw IllegalPropertyAccessException(e)
|
||||
@@ -44,27 +41,20 @@ open class KTopLevelExtensionPropertyImpl<T, out R>(
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KTopLevelExtensionPropertyImpl<*, *> && name == other.name && owner == other.owner && receiverClass == other.receiverClass
|
||||
other is KTopLevelExtensionPropertyImpl<*, *> && descriptor == other.descriptor
|
||||
|
||||
override fun hashCode(): Int =
|
||||
(name.hashCode() * 31 + owner.hashCode()) * 31 + receiverClass.hashCode()
|
||||
descriptor.hashCode()
|
||||
|
||||
// TODO: include visibility, return type, maybe package
|
||||
override fun toString(): String =
|
||||
"val ${mapJavaClassToKotlin(receiverClass.getName())}.$name"
|
||||
ReflectionObjectRenderer.renderProperty(descriptor)
|
||||
}
|
||||
|
||||
class KMutableTopLevelExtensionPropertyImpl<T, R>(
|
||||
name: String,
|
||||
owner: KPackageImpl,
|
||||
receiverClass: Class<T>
|
||||
) : KMutableTopLevelExtensionProperty<T, R>, KMutablePropertyImpl<R>, KTopLevelExtensionPropertyImpl<T, R>(name, owner, receiverClass) {
|
||||
override val setter: Method = try {
|
||||
owner.jClass.getMethod(setterName(name), receiverClass, getter.getReturnType())
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
throw NoSuchPropertyException(e)
|
||||
}
|
||||
container: KPackageImpl,
|
||||
computeDescriptor: () -> PropertyDescriptor
|
||||
) : KTopLevelExtensionPropertyImpl<T, R>(container, computeDescriptor), KMutableTopLevelExtensionProperty<T, R>, KMutablePropertyImpl<R> {
|
||||
override val setter: Method get() = super<KTopLevelExtensionPropertyImpl>.setter!!
|
||||
|
||||
override fun set(receiver: T, value: R) {
|
||||
try {
|
||||
@@ -74,39 +64,4 @@ class KMutableTopLevelExtensionPropertyImpl<T, R>(
|
||||
throw IllegalPropertyAccessException(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"var ${mapJavaClassToKotlin(receiverClass.getName())}.$name"
|
||||
}
|
||||
|
||||
private fun mapJavaClassToKotlin(name: String): String {
|
||||
if (name[0].isLowerCase()) {
|
||||
return when (name) {
|
||||
"boolean" -> "kotlin.Boolean"
|
||||
"char" -> "kotlin.Char"
|
||||
"byte" -> "kotlin.Byte"
|
||||
"short" -> "kotlin.Short"
|
||||
"int" -> "kotlin.Int"
|
||||
"float" -> "kotlin.Float"
|
||||
"long" -> "kotlin.Long"
|
||||
"double" -> "kotlin.Double"
|
||||
else -> name
|
||||
}
|
||||
}
|
||||
if (name[0] == '[') {
|
||||
val element = name.substring(1)
|
||||
return when (element[0]) {
|
||||
'Z' -> "kotlin.BooleanArray"
|
||||
'C' -> "kotlin.CharArray"
|
||||
'B' -> "kotlin.ByteArray"
|
||||
'S' -> "kotlin.ShortArray"
|
||||
'I' -> "kotlin.IntArray"
|
||||
'F' -> "kotlin.FloatArray"
|
||||
'J' -> "kotlin.LongArray"
|
||||
'D' -> "kotlin.DoubleArray"
|
||||
'L' -> "kotlin.Array<${mapJavaClassToKotlin(element.substring(1, element.length() - 1))}>"
|
||||
else -> "kotlin.Array<${mapJavaClassToKotlin(element)}>"
|
||||
}
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.desc
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMapBuilder
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
|
||||
object RuntimeTypeMapper : JavaToKotlinClassMapBuilder() {
|
||||
private val kotlinFqNameToJvmDesc = linkedMapOf<FqName, String>()
|
||||
private val kotlinFqNameToJvmDescNullable = linkedMapOf<FqName, String>()
|
||||
private val jvmDescToKotlinClassId = linkedMapOf<String, ClassId>();
|
||||
|
||||
{
|
||||
init()
|
||||
initPrimitives()
|
||||
}
|
||||
|
||||
private fun initPrimitives() {
|
||||
val builtIns = KotlinBuiltIns.getInstance()
|
||||
|
||||
for (type in JvmPrimitiveType.values()) {
|
||||
val primitiveType = type.getPrimitiveType()
|
||||
val primitiveClassDescriptor = builtIns.getPrimitiveClassDescriptor(primitiveType)
|
||||
|
||||
recordMapping(primitiveClassDescriptor, type.getDesc())
|
||||
recordMapping(builtIns.getPrimitiveArrayClassDescriptor(primitiveType), "[" + type.getDesc())
|
||||
|
||||
recordNullableMapping(primitiveClassDescriptor, ClassId.topLevel(type.getWrapperFqName()).desc)
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordMapping(kotlinDescriptor: ClassDescriptor, jvmDesc: String) {
|
||||
kotlinFqNameToJvmDesc[DescriptorUtils.getFqNameSafe(kotlinDescriptor)] = jvmDesc
|
||||
jvmDescToKotlinClassId[jvmDesc] = kotlinDescriptor.classId
|
||||
|
||||
val defaultObject = kotlinDescriptor.getDefaultObjectDescriptor()
|
||||
if (defaultObject != null) {
|
||||
// TODO: see org.jetbrains.kotlin.codegen.intrinsics.IntrinsicObjects, extract that logic to core/
|
||||
recordMapping(defaultObject, "Lkotlin/jvm/internal/${kotlinDescriptor.getName().asString()}DefaultObject;")
|
||||
}
|
||||
}
|
||||
|
||||
private fun recordNullableMapping(kotlinDescriptor: ClassDescriptor, jvmDesc: String) {
|
||||
kotlinFqNameToJvmDescNullable[DescriptorUtils.getFqNameSafe(kotlinDescriptor)] = jvmDesc
|
||||
jvmDescToKotlinClassId[jvmDesc] = kotlinDescriptor.classId
|
||||
}
|
||||
|
||||
override fun register(javaClass: Class<*>, kotlinDescriptor: ClassDescriptor, direction: JavaToKotlinClassMapBuilder.Direction) {
|
||||
recordMapping(kotlinDescriptor, javaClass.classId.desc)
|
||||
}
|
||||
|
||||
override fun register(javaClass: Class<*>, kotlinDescriptor: ClassDescriptor, kotlinMutableDescriptor: ClassDescriptor) {
|
||||
// TODO: readonly collection mapping just rewrites the mutable one, improve readability here
|
||||
register(javaClass, kotlinMutableDescriptor, JavaToKotlinClassMapBuilder.Direction.BOTH)
|
||||
register(javaClass, kotlinDescriptor, JavaToKotlinClassMapBuilder.Direction.BOTH)
|
||||
}
|
||||
|
||||
fun mapTypeToJvmDesc(type: JetType): String {
|
||||
val classifier = type.getConstructor().getDeclarationDescriptor()
|
||||
if (classifier is TypeParameterDescriptor) return mapTypeToJvmDesc(classifier.getUpperBounds().first())
|
||||
|
||||
val classDescriptor = classifier as ClassDescriptor
|
||||
val fqNameUnsafe = DescriptorUtils.getFqName(classDescriptor)
|
||||
if (fqNameUnsafe.isSafe()) {
|
||||
val fqName = fqNameUnsafe.toSafe()
|
||||
if (TypeUtils.isNullableType(type)) {
|
||||
kotlinFqNameToJvmDescNullable[fqName]?.let { return it }
|
||||
}
|
||||
kotlinFqNameToJvmDesc[fqName]?.let { return it }
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
var dimension = 0
|
||||
var elementType = type
|
||||
|
||||
while (KotlinBuiltIns.isArray(elementType)) {
|
||||
elementType = KotlinBuiltIns.getInstance().getArrayElementType(elementType)
|
||||
dimension++
|
||||
}
|
||||
|
||||
return "[".repeat(dimension) + mapTypeToJvmDesc(TypeUtils.makeNullable(elementType))
|
||||
}
|
||||
|
||||
return classDescriptor.classId.desc
|
||||
}
|
||||
|
||||
fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId {
|
||||
return jvmDescToKotlinClassId[klass.desc] ?: klass.classId
|
||||
}
|
||||
|
||||
private val ClassId.desc: String
|
||||
get() = "L${JvmClassName.byClassId(this).getInternalName()};"
|
||||
}
|
||||
@@ -28,14 +28,6 @@ import java.lang.reflect.Field
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
|
||||
private fun String.capitalizeWithJavaBeanConvention(): String {
|
||||
if (length() > 1 && Character.isUpperCase(this[1])) return this
|
||||
return Character.toUpperCase(this[0]) + substring(1, length())
|
||||
}
|
||||
|
||||
private fun getterName(propertyName: String): String = "get" + propertyName.capitalizeWithJavaBeanConvention()
|
||||
private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention()
|
||||
|
||||
|
||||
private fun Class<*>.getMaybeDeclaredMethod(name: String, vararg parameterTypes: Class<*>): Method {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user