From 9ad3922c7d01d7904f28228dc7d61b92f9917dd1 Mon Sep 17 00:00:00 2001 From: Leonid Startsev Date: Wed, 6 Jun 2018 15:19:25 +0300 Subject: [PATCH] Fix 1.2.50 compatibility Updated version to 0.5.1 Fix resolving serializers for classes from other modules (Kotlin/kotlinx.serialization/153) Respect @SerialName on classes Add support for @SerialInfo on class-level --- .../tools/kotlin-maven-serialization/pom.xml | 2 +- .../tools/kotlin-serialization/build.gradle | 2 +- .../kotlin-serialization-compiler/README.md | 4 +- .../src/META-INF/plugin.xml | 2 +- .../backend/common/SerializerCodegen.kt | 2 +- .../backend/js/SerializerJsTranslator.kt | 24 ++++++--- .../backend/jvm/SerializerCodegenImpl.kt | 53 ++++++++++++------- .../compiler/resolve/KSerializationUtil.kt | 17 +++++- .../resolve/SerializableProperties.kt | 4 +- .../compiler/resolve/SerializableProperty.kt | 11 +--- 10 files changed, 75 insertions(+), 46 deletions(-) diff --git a/libraries/tools/kotlin-maven-serialization/pom.xml b/libraries/tools/kotlin-maven-serialization/pom.xml index ddcc00b6962..276b806feb4 100755 --- a/libraries/tools/kotlin-maven-serialization/pom.xml +++ b/libraries/tools/kotlin-maven-serialization/pom.xml @@ -19,7 +19,7 @@ org.jetbrains.kotlinx kotlinx-maven-serialization-plugin jar - 0.5.0 + 0.5.2-SNAPSHOT Serialization plugin for Maven diff --git a/libraries/tools/kotlin-serialization/build.gradle b/libraries/tools/kotlin-serialization/build.gradle index d6afcd7da8b..82164013133 100644 --- a/libraries/tools/kotlin-serialization/build.gradle +++ b/libraries/tools/kotlin-serialization/build.gradle @@ -8,7 +8,7 @@ configureJvmProject(project) configurePublishing(project) group = 'org.jetbrains.kotlinx' -version = '0.5.0' +version = '0.5.2' if (!project.hasProperty("deploy")) { version = "$version-SNAPSHOT" } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md b/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md index bb31a32e291..e1c22d6f49b 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/README.md @@ -8,7 +8,7 @@ Compiler plugins are uploaded on bintray: https://bintray.com/kotlin/kotlinx/kot ## Building and usage ### Prerequisites: -Before all, follow the instructions from root README.md to download dependencies and build Kotlin compiler. (`ant -f update_dependencies.xml && ./gradlew dist`) +Before all, follow the instructions from root README.md to download dependencies and build Kotlin compiler. (`./gradlew dist`) **Plugin works only with IntelliJIDEA 2017.2 and higher.** @@ -29,5 +29,5 @@ Run `./gradlew :kotlinx-gradle-serialization-plugin:install` ## Building maven plugin -Go to `$kotlin_root/libraries/tools/kotlin-maven-serialization`. Run `mvn install` +Make all prerequisites from libraries' README.md for Maven projects. Go to `$kotlin_root/libraries/tools/kotlin-maven-serialization`. Run `mvn install` diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml index 71c492bf9f9..fa08b08e9ef 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/META-INF/plugin.xml @@ -1,7 +1,7 @@ Kotlin-serialization org.jetbrains.kotlinx.serialization - 0.5.0 + 0.5.2-SNAPSHOT org.jetbrains.kotlin diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt index 3fc779ec541..fcdabed30c3 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/common/SerializerCodegen.kt @@ -30,7 +30,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescripto abstract class SerializerCodegen(declaration: KtPureClassOrObject, bindingContext: BindingContext) { protected val serializerDescriptor: ClassDescriptor = declaration.findClassDescriptor(bindingContext) protected val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!! - protected val serialName: String = serializableDescriptor.fqNameUnsafe.asString() + protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString() protected val properties = SerializableProperties(serializableDescriptor, bindingContext) protected val orderedProperties = properties.serializableProperties diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt index 6c4296a6696..014ab3faa32 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/js/SerializerJsTranslator.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.js import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.js.backend.ast.* import org.jetbrains.kotlin.js.translate.context.Namer import org.jetbrains.kotlin.js.translate.context.TranslationContext @@ -26,7 +27,6 @@ import org.jetbrains.kotlin.js.translate.declaration.DefaultPropertyTranslator import org.jetbrains.kotlin.js.translate.general.Translation import org.jetbrains.kotlin.js.translate.utils.JsAstUtils import org.jetbrains.kotlin.js.translate.utils.TranslationUtils -import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtPureClassOrObject import org.jetbrains.kotlin.resolve.descriptorUtil.classId @@ -67,6 +67,7 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, // adding elements via serialDesc.addElement(...) val addFunc = serialDescImplClass.getFuncDesc("addElement").single() val pushFunc = serialDescImplClass.getFuncDesc("pushAnnotation").single() + val pushClassFunc = serialDescImplClass.getFuncDesc("pushClassAnnotation").single() val serialClassDescRef = JsNameRef(context.getNameForDescriptor(serialDescPropertyDescriptor), JsThisRef()) for (prop in orderedProperties) { @@ -74,14 +75,21 @@ class SerializerJsTranslator(declaration: KtPureClassOrObject, val call = JsInvocation(JsNameRef(context.getNameForDescriptor(addFunc), serialClassDescRef), JsStringLiteral(prop.name)) translator.addInitializerStatement(call.makeStmt()) // serialDesc.pushAnnotation(...) - for ((annotationClass , args, _) in prop.annotationsWithArguments) { - val argExprs = args.map { arg -> - Translation.translateAsExpression(arg.getArgumentExpression()!!, context) - } - val classRef = context.translateQualifiedReference(annotationClass) - val invok = JsInvocation(JsNameRef(context.getNameForDescriptor(pushFunc), serialClassDescRef), JsNew(classRef, argExprs)) - translator.addInitializerStatement(invok.makeStmt()) + pushAnnotationsInto(prop.descriptor, pushFunc, serialClassDescRef) + } + + // push class annotations + pushAnnotationsInto(serializableDescriptor, pushClassFunc, serialClassDescRef) + } + + private fun pushAnnotationsInto(annotated: Annotated, pushFunction: DeclarationDescriptor, intoRef: JsNameRef) { + for ((annotationClass , args, _) in annotated.annotationsWithArguments()) { + val argExprs = args.map { arg -> + Translation.translateAsExpression(arg.getArgumentExpression()!!, context) } + val classRef = context.translateQualifiedReference(annotationClass) + val invok = JsInvocation(JsNameRef(context.getNameForDescriptor(pushFunction), intoRef), JsNew(classRef, argExprs)) + translator.addInitializerStatement(invok.makeStmt()) } } diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt index 9d533cb06d3..cd057cdc4c9 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/backend/jvm/SerializerCodegenImpl.kt @@ -17,15 +17,14 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm import org.jetbrains.kotlin.codegen.* -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ConstructorDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.jvm.AsmTypes import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializerCodegen import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver import org.jetbrains.kotlinx.serialization.compiler.resolve.KSerializerDescriptorResolver.typeArgPrefix +import org.jetbrains.kotlinx.serialization.compiler.resolve.annotationsWithArguments import org.jetbrains.kotlinx.serialization.compiler.resolve.getSerializableClassDescriptorBySerializer import org.jetbrains.kotlinx.serialization.compiler.resolve.isInternalSerializable import org.jetbrains.org.objectweb.asm.Label @@ -91,29 +90,45 @@ class SerializerCodegenImpl( for ((annotationClass, args, consParams) in property.annotationsWithArguments) { if (args.size != consParams.size) throw IllegalArgumentException("Can't use arguments with defaults for serializable annotations yet") load(classDescVar, descImplType) - val implType = codegen.typeMapper.mapType(annotationClass).internalName + "\$" + KSerializerDescriptorResolver.IMPL_NAME.identifier - // new Annotation$Impl(...) - anew(Type.getObjectType(implType)) - dup() - val sb = StringBuilder("(") - for (i in consParams.indices) { - val decl = args[i] - val desc = consParams[i] - val valAsmType = codegen.typeMapper.mapType(desc.type) - expr.gen(decl.getArgumentExpression(), valAsmType) - sb.append(valAsmType.descriptor) - } - sb.append(")V") - invokespecial(implType, "", sb.toString(), false) - // serialDesc.pushAnnotation(..) + expr.generateSyntheticAnnotationOnStack(annotationClass, args, consParams) invokevirtual(descImplType.internalName, "pushAnnotation", "(Ljava/lang/annotation/Annotation;)V", false) } } + // add annotations on class itself + for ((annotationClass, args, consParams) in serializableDescriptor.annotationsWithArguments()) { + if (args.size != consParams.size) throw IllegalArgumentException("Can't use arguments with defaults for serializable annotations yet") + load(classDescVar, descImplType) + expr.generateSyntheticAnnotationOnStack(annotationClass, args, consParams) + invokevirtual(descImplType.internalName, "pushClassAnnotation", "(Ljava/lang/annotation/Annotation;)V", false) + } load(classDescVar, descImplType) putstatic(serializerAsmType.internalName, serialDescField, descType.descriptor) } } + private fun ExpressionCodegen.generateSyntheticAnnotationOnStack( + annotationClass: ClassDescriptor, + args: List, + ctorParams: List + ) { + val implType = codegen.typeMapper.mapType(annotationClass).internalName + "\$" + KSerializerDescriptorResolver.IMPL_NAME.identifier + with(v) { + // new Annotation$Impl(...) + anew(Type.getObjectType(implType)) + dup() + val sb = StringBuilder("(") + for (i in ctorParams.indices) { + val decl = args[i] + val desc = ctorParams[i] + val valAsmType = codegen.typeMapper.mapType(desc.type) + this@generateSyntheticAnnotationOnStack.gen(decl.getArgumentExpression(), valAsmType) + sb.append(valAsmType.descriptor) + } + sb.append(")V") + invokespecial(implType, "", sb.toString(), false) + } + } + private fun InstructionAdapter.serialCLassDescToLocalVar(classDescVar: Int) { getstatic(serializerAsmType.internalName, serialDescField, descType.descriptor) store(classDescVar, descType) diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt index 8ce11e9609e..18f2fd67ac5 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/KSerializationUtil.kt @@ -18,10 +18,12 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotated import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.descriptorUtil.module import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered @@ -124,8 +126,10 @@ val KotlinType?.toClassDescriptor: ClassDescriptor? val ClassDescriptor.isInternalSerializable: Boolean //todo normal checking get() { if (!annotations.hasAnnotation(serializableAnnotationFqName)) return false + // If provided descriptor is lazy, carefully look at psi in order not to trigger full resolve which may be recursive. + // Otherwise, this descriptor is deserialized from another module and it is OK to check value right away. val lazyDesc = annotations.findAnnotation(serializableAnnotationFqName) - as? LazyAnnotationDescriptor ?: return false + as? LazyAnnotationDescriptor ?: return (annotations.serializableWith == null) val psi = lazyDesc.annotationEntry return psi.valueArguments.isEmpty() } @@ -232,3 +236,14 @@ fun ClassDescriptor.getClassFromInternalSerializationPackage(classSimpleName: St module.getClassFromInternalSerializationPackage(classSimpleName) fun ClassDescriptor.toSimpleType(nullable: Boolean = true) = KotlinTypeFactory.simpleType(Annotations.EMPTY, this.typeConstructor, emptyList(), nullable) + +fun Annotated.annotationsWithArguments(): List, List>> = + annotations.asSequence() + .filter { it.type.toClassDescriptor?.annotations?.hasAnnotation(serialInfoFqName) == true } + .filterIsInstance() + .mapNotNull { annDesc -> + annDesc.type.toClassDescriptor?.let { + Triple(it, annDesc.annotationEntry.valueArguments, it.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty()) + } + } + .toList() diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt index 487b7b3e477..c4a7a7dc057 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperties.kt @@ -19,7 +19,6 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny -import org.jetbrains.kotlin.resolve.descriptorUtil.hasOwnParametersWithDefaultValue import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) { @@ -71,5 +70,6 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val operator fun get(index: Int) = serializableProperties[index] operator fun iterator() = serializableProperties.iterator() - val primaryConstructorWithDefaults = serializableClass.unsubstitutedPrimaryConstructor?.hasOwnParametersWithDefaultValue() ?: false + val primaryConstructorWithDefaults = serializableClass.unsubstitutedPrimaryConstructor + ?.original?.valueParameters?.any { it.declaresDefaultValue() } ?: false } \ No newline at end of file diff --git a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt index ba6a9dd1972..706810159fe 100644 --- a/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt +++ b/plugins/kotlin-serialization/kotlin-serialization-compiler/src/org/jetbrains/kotlinx/serialization/compiler/resolve/SerializableProperty.kt @@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.resolve.descriptorUtil.module -import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructorParameterWithDefault: Boolean) { val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString() @@ -32,13 +31,5 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor val optional = descriptor.annotations.serialOptional val transient = descriptor.annotations.serialTransient val annotationsWithArguments: List, List>> = - descriptor.annotations.asSequence() - .filter { it.type.toClassDescriptor?.annotations?.hasAnnotation(serialInfoFqName) == true } - .filterIsInstance() - .mapNotNull { annDesc -> - annDesc.type.toClassDescriptor?.let { - Triple(it, annDesc.annotationEntry.valueArguments, it.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty()) - } - } - .toList() + descriptor.annotationsWithArguments() }