Support Java symbols in runtime descriptor loading

This commit is contained in:
Alexander Udalov
2014-08-29 18:35:13 +04:00
parent 73e4287aee
commit c90f11b7e6
19 changed files with 4018 additions and 2688 deletions
@@ -26,7 +26,13 @@ import org.jetbrains.kotlin.name.ClassId
public class ReflectJavaClassFinder(private val classLoader: ClassLoader) : JavaClassFinder {
override fun findClass(classId: ClassId): JavaClass? {
val klass = classLoader.tryLoadClass(classId.asSingleFqName().asString())
val packageFqName = classId.getPackageFqName()
val relativeClassName = classId.getRelativeClassName().asString().replace('.', '$')
val name =
if (packageFqName.isRoot()) relativeClassName
else packageFqName.asString() + "." + relativeClassName
val klass = classLoader.tryLoadClass(name)
return if (klass != null) ReflectJavaClass(klass) else null
}
@@ -0,0 +1,40 @@
/*
* 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 org.jetbrains.kotlin.load.java.structure.reflect
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument
import org.jetbrains.kotlin.name.Name
import java.lang.reflect.Method
public class ReflectJavaAnnotation(private val annotation: Annotation) : ReflectJavaElement(), JavaAnnotation {
override fun findArgument(name: Name): JavaAnnotationArgument? {
return getArgumentValue(annotation.annotationType().getDeclaredMethod(name.asString()))
}
override fun getArguments(): Collection<JavaAnnotationArgument> {
return annotation.annotationType().getDeclaredMethods().map { getArgumentValue(it) }
}
private fun getArgumentValue(argument: Method): ReflectJavaAnnotationArgument {
return argument.invoke(annotation).let { ReflectJavaAnnotationArgument.create(it, Name.identifier(argument.getName())) }
}
override fun resolve() = ReflectJavaClass(annotation.annotationType())
override fun getClassId() = annotation.annotationType().classId
}
@@ -0,0 +1,69 @@
/*
* 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 org.jetbrains.kotlin.load.java.structure.reflect
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
abstract class ReflectJavaAnnotationArgument(
override val name: Name?
) : JavaAnnotationArgument {
class object {
fun create(value: Any, name: Name?): ReflectJavaAnnotationArgument {
return when {
value.javaClass.isEnum() -> ReflectJavaEnumValueAnnotationArgument(name, value)
value is Annotation -> ReflectJavaAnnotationAsAnnotationArgument(name, value)
value is Array<Any> -> ReflectJavaArrayAnnotationArgument(name, value)
value is Class<*> -> ReflectJavaClassObjectAnnotationArgument(name, value)
else -> ReflectJavaLiteralAnnotationArgument(name, value)
}
}
}
}
class ReflectJavaLiteralAnnotationArgument(
name: Name?,
override val value: Any
) : ReflectJavaAnnotationArgument(name), JavaLiteralAnnotationArgument
class ReflectJavaArrayAnnotationArgument(
name: Name?,
private val values: Array<Any>
) : ReflectJavaAnnotationArgument(name), JavaArrayAnnotationArgument {
override fun getElements() = values.map { ReflectJavaAnnotationArgument.create(it, null) }
}
class ReflectJavaEnumValueAnnotationArgument(
name: Name?,
private val value: Any
) : ReflectJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument {
override fun resolve() = ReflectJavaField(value.javaClass.getDeclaredField(value.toString()))
}
class ReflectJavaClassObjectAnnotationArgument(
name: Name?,
private val klass: Class<*>
) : ReflectJavaAnnotationArgument(name), JavaClassObjectAnnotationArgument {
override fun getReferencedType(): JavaType = ReflectJavaType.create(klass)
}
class ReflectJavaAnnotationAsAnnotationArgument(
name: Name?,
private val annotation: Annotation
) : ReflectJavaAnnotationArgument(name), JavaAnnotationAsAnnotationArgument {
override fun getAnnotation(): JavaAnnotation = ReflectJavaAnnotation(annotation)
}
@@ -16,9 +16,9 @@
package org.jetbrains.kotlin.load.java.structure.reflect
import java.lang.reflect.GenericArrayType
import org.jetbrains.kotlin.load.java.structure.JavaArrayType
import java.lang.reflect.Type
public class ReflectJavaArrayType(private val arrayType: GenericArrayType) : ReflectJavaType(), JavaArrayType {
override fun getComponentType() = ReflectJavaType.create(arrayType.getGenericComponentType()!!)
public class ReflectJavaArrayType(private val componentType: Type) : ReflectJavaType(), JavaArrayType {
override fun getComponentType() = ReflectJavaType.create(componentType)
}
@@ -16,69 +16,88 @@
package org.jetbrains.kotlin.load.java.structure.reflect
import java.lang.reflect.Modifier
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.emptyOrSingletonList
import java.lang.reflect.Method
import java.lang.reflect.Modifier
import java.util.Arrays
public class ReflectJavaClass(private val klass: Class<*>) : ReflectJavaElement(), JavaClass {
override fun getInnerClasses() =
klass.getDeclaredClasses()
.filter { it.getSimpleName().isNotEmpty() }
.map { ReflectJavaClass(it) }
override fun getInnerClasses() = klass.getDeclaredClasses()
.stream()
.filterNot {
// getDeclaredClasses() returns anonymous classes sometimes, for example enums with specialized entries (which are in fact
// anonymous classes) or in case of a special anonymous class created for the synthetic accessor to a private nested class
// constructor accessed from the outer class
it.getSimpleName().isEmpty()
}
.map(::ReflectJavaClass)
.toList()
override fun getFqName(): FqName? {
// TODO: can there be primitive types, arrays?
return getOuterClass()?.getFqName()?.child(Name.identifier(klass.getSimpleName())) ?: FqName(klass.getName())
}
override fun getFqName() = klass.fqName
override fun getOuterClass(): JavaClass? {
val container = klass.getDeclaringClass()
return if (container != null) ReflectJavaClass(container) else null
}
override fun getOuterClass() = klass.getDeclaringClass()?.let(::ReflectJavaClass)
override fun getSupertypes(): Collection<JavaClassifierType> {
// TODO: also call getSuperclass() / getInterfaces() for classes without generic signature
val supertypes = emptyOrSingletonList(klass.getGenericSuperclass()) + klass.getGenericInterfaces()
return supertypes.map { supertype -> ReflectJavaType.create(supertype) as JavaClassifierType }
val supertype = klass.getGenericSuperclass()
val superClassName = (supertype as? Class<*>)?.getName()
val supertypes =
(if (superClassName == "java.lang.Object") emptyList() else emptyOrSingletonList(supertype)) +
klass.getGenericInterfaces()
return supertypes.map(::ReflectJavaClassifierType)
}
override fun getMethods() = klass.getDeclaredMethods().map { method -> ReflectJavaMethod(method) }
override fun getMethods() = klass.getDeclaredMethods()
.stream()
.filter { method ->
when {
method.isSynthetic() -> false
isEnum() -> !isEnumValuesOrValueOf(method)
else -> true
}
}
.map(::ReflectJavaMethod)
.toList()
override fun getFields() = klass.getDeclaredFields().map { field -> ReflectJavaField(field) }
override fun getConstructors(): Collection<JavaConstructor> {
// TODO
return listOf()
private fun isEnumValuesOrValueOf(method: Method): Boolean {
return when (method.getName()) {
"values" -> method.getParameterTypes().isEmpty()
"valueOf" -> Arrays.equals(method.getParameterTypes(), array(javaClass<String>()))
else -> false
}
}
override fun getDefaultType() = ReflectJavaClassifierType(klass)
override fun getFields() = klass.getDeclaredFields()
.stream()
.filter { field -> !field.isSynthetic() }
.map(::ReflectJavaField)
.toList()
// TODO: drop OriginKind?
override fun getConstructors() = klass.getDeclaredConstructors().map(::ReflectJavaConstructor)
override fun getDefaultType(): ReflectJavaClassifierType = throw UnsupportedOperationException()
// TODO: drop OriginKind
override fun getOriginKind() = JavaClass.OriginKind.COMPILED
override fun createImmediateType(substitutor: JavaTypeSubstitutor): JavaType {
// TODO
throw UnsupportedOperationException()
}
override fun createImmediateType(substitutor: JavaTypeSubstitutor): JavaType = throw UnsupportedOperationException()
override fun getName(): Name {
// TODO: can there be primitive types, arrays?
return Name.identifier(klass.getSimpleName())
}
override fun getName(): Name = Name.identifier(klass.getSimpleName())
override fun getAnnotations(): Collection<JavaAnnotation> {
// TODO
return listOf()
}
override fun getAnnotations() = klass.getDeclaredAnnotations().map { ReflectJavaAnnotation(it) }
override fun findAnnotation(fqName: FqName): JavaAnnotation? {
// TODO
for (annotation in klass.getDeclaredAnnotations()) {
if (annotation.annotationType().fqName == fqName) {
return ReflectJavaAnnotation(annotation)
}
}
return null
}
override fun getTypeParameters() = klass.getTypeParameters().map { ReflectJavaTypeParameter(it!!) }
override fun getTypeParameters() = klass.getTypeParameters().map { ReflectJavaTypeParameter(it) }
override fun isInterface() = klass.isInterface()
override fun isAnnotationType() = klass.isAnnotation()
@@ -25,15 +25,18 @@ import java.lang.reflect.Type
import java.lang.reflect.TypeVariable
public class ReflectJavaClassifierType(val classifierType: Type) : ReflectJavaType(), JavaClassifierType {
override fun getClassifier(): JavaClassifier? {
return when (classifierType) {
is Class<*> -> ReflectJavaClass(classifierType)
is TypeVariable<*> -> ReflectJavaTypeParameter(classifierType)
is ParameterizedType -> ReflectJavaClass(classifierType.getRawType() as Class<*>)
else -> throw IllegalStateException("Not a classifier type (${classifierType.javaClass}): $classifierType")
}
private val classifier: JavaClassifier = run {
val type = classifierType
when (type) {
is Class<*> -> ReflectJavaClass(type)
is TypeVariable<*> -> ReflectJavaTypeParameter(type)
is ParameterizedType -> ReflectJavaClass(type.getRawType() as Class<*>)
else -> throw IllegalStateException("Not a classifier type (${type.javaClass}): $type")
} : JavaClassifier
}
override fun getClassifier(): JavaClassifier = classifier
override fun getSubstitutor(): JavaTypeSubstitutor = throw UnsupportedOperationException()
override fun getSupertypes(): Collection<JavaClassifierType> = throw UnsupportedOperationException()
@@ -0,0 +1,63 @@
/*
* 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 org.jetbrains.kotlin.load.java.structure.reflect
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.load.java.structure.JavaConstructor
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.FqName
import java.lang.reflect.Constructor
import java.lang.reflect.Modifier
import java.util.Arrays
public class ReflectJavaConstructor(constructor: Constructor<*>) : ReflectJavaMember(constructor), JavaConstructor {
private val constructor: Constructor<*>
get() = member as Constructor<*>
override fun getAnnotations(): Collection<JavaAnnotation> {
// TODO
return listOf()
}
override fun findAnnotation(fqName: FqName): JavaAnnotation? {
// TODO
return null
}
override fun getValueParameters(): List<JavaValueParameter> =
getValueParameters(
dropSynthetic(constructor.getGenericParameterTypes()),
dropSynthetic(constructor.getParameterAnnotations()),
constructor.isVarArgs()
)
// Constructors of inner classes have one additional synthetic parameter
// TODO: test this code with annotations on constructor parameters of enums and inner classes
private inline fun <reified T> dropSynthetic(array: Array<T>): Array<T> {
val klass = constructor.getDeclaringClass()
return if (klass.getDeclaringClass() != null && !Modifier.isStatic(klass.getModifiers())) {
Arrays.copyOfRange(array, 1, array.size())
}
else array
}
override fun getTypeParameters(): List<JavaTypeParameter> {
// TODO
return listOf()
}
}
@@ -20,7 +20,6 @@ import java.lang.reflect.Field
import org.jetbrains.kotlin.load.java.structure.JavaField
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.load.java.structure.JavaType
public class ReflectJavaField(field: Field) : ReflectJavaMember(field), JavaField {
val field: Field
@@ -38,8 +37,5 @@ public class ReflectJavaField(field: Field) : ReflectJavaMember(field), JavaFiel
override fun isEnumEntry() = field.isEnumConstant()
override fun getType(): JavaType {
// TODO
throw UnsupportedOperationException()
}
override fun getType() = ReflectJavaType.create(field.getGenericType()!!)
}
@@ -16,11 +16,14 @@
package org.jetbrains.kotlin.load.java.structure.reflect
import java.lang.reflect.Member
import java.lang.reflect.Modifier
import org.jetbrains.kotlin.load.java.structure.JavaMember
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import java.lang.reflect.Member
import java.lang.reflect.Modifier
import java.lang.reflect.Type
import java.util.ArrayList
public abstract class ReflectJavaMember(protected val member: Member) : ReflectJavaElement(), JavaMember {
override fun getName() = member.getName()?.let { Name.identifier(it) } ?: SpecialNames.NO_NAME_PROVIDED
@@ -32,4 +35,17 @@ public abstract class ReflectJavaMember(protected val member: Member) : ReflectJ
override fun isFinal() = Modifier.isFinal(member.getModifiers())
override fun getVisibility() = calculateVisibility(member.getModifiers())
protected fun getValueParameters(
parameterTypes: Array<Type>,
parameterAnnotations: Array<Array<Annotation>>,
isVararg: Boolean
): List<JavaValueParameter> {
val result = ArrayList<JavaValueParameter>(parameterTypes.size())
for (i in parameterTypes.indices) {
val isParamVararg = isVararg && i == parameterTypes.lastIndex
result.add(ReflectJavaValueParameter(ReflectJavaType.create(parameterTypes[i]), parameterAnnotations[i], isParamVararg))
}
return result
}
}
@@ -16,13 +16,12 @@
package org.jetbrains.kotlin.load.java.structure.reflect
import java.lang.reflect.Method
import java.util.ArrayList
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.load.java.structure.JavaMethod
import org.jetbrains.kotlin.load.java.structure.JavaType
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter
import org.jetbrains.kotlin.name.FqName
import java.lang.reflect.Method
public class ReflectJavaMethod(method: Method) : ReflectJavaMember(method), JavaMethod {
private val method: Method
@@ -38,17 +37,8 @@ public class ReflectJavaMethod(method: Method) : ReflectJavaMember(method), Java
return null
}
override fun getValueParameters(): List<JavaValueParameter> {
val types = method.getGenericParameterTypes()!!
val annotations = method.getParameterAnnotations()
val result = ArrayList<JavaValueParameter>()
val methodIsVararg = method.isVarArgs()
for (i in types.indices) {
val isVararg = methodIsVararg && i == types.lastIndex
result.add(ReflectJavaValueParameter(ReflectJavaType.create(types[i]), annotations[i], isVararg))
}
return result
}
override fun getValueParameters(): List<JavaValueParameter> =
getValueParameters(method.getGenericParameterTypes(), method.getParameterAnnotations(), method.isVarArgs())
override fun getReturnType(): JavaType? {
// TODO
@@ -33,8 +33,12 @@ public abstract class ReflectJavaType : JavaType {
fun create(reflectType: Type): ReflectJavaType {
return when (reflectType) {
in PRIMITIVE_TYPES -> ReflectJavaPrimitiveType(reflectType as Class<*>)
is Class<*>, is TypeVariable<*>, is ParameterizedType -> ReflectJavaClassifierType(reflectType)
is GenericArrayType -> ReflectJavaArrayType(reflectType)
is GenericArrayType -> ReflectJavaArrayType(reflectType.getGenericComponentType()!!)
is Class<*> -> {
if (reflectType.isArray()) ReflectJavaArrayType(reflectType.getComponentType()!!)
else ReflectJavaClassifierType(reflectType)
}
is TypeVariable<*>, is ParameterizedType -> ReflectJavaClassifierType(reflectType)
is WildcardType -> ReflectJavaWildcardType(reflectType)
else -> throw UnsupportedOperationException("Unsupported type (${reflectType.javaClass}): $reflectType")
}
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.load.java.structure.JavaType
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameterListOwner
import org.jetbrains.kotlin.name.Name
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import java.lang.reflect.TypeVariable
@@ -35,8 +36,9 @@ public class ReflectJavaTypeParameter(
override fun getOwner(): JavaTypeParameterListOwner? {
val owner = typeVariable.getGenericDeclaration()
return when (owner) {
is Method -> ReflectJavaMethod(owner)
is Class<*> -> ReflectJavaClass(owner)
is Method -> ReflectJavaMethod(owner)
is Constructor<*> -> ReflectJavaConstructor(owner)
else -> throw UnsupportedOperationException("Unsupported type parameter list owner (${owner.javaClass}): $owner")
}
}
@@ -16,13 +16,13 @@
package org.jetbrains.kotlin.load.java.structure.reflect
import java.lang.reflect.Modifier
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import java.lang.reflect.Modifier
private fun calculateVisibility(modifiers: Int): Visibility {
return when {
@@ -34,5 +34,8 @@ private fun calculateVisibility(modifiers: Int): Visibility {
}
}
val Class<*>.classId: ClassId
public val Class<*>.fqName: FqName
get() = classId.asSingleFqName().toSafe()
public val Class<*>.classId: ClassId
get() = getDeclaringClass()?.classId?.createNestedClassId(Name.identifier(getSimpleName())) ?: ClassId.topLevel(FqName(getName()))