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
This commit is contained in:
Leonid Startsev
2018-06-06 15:19:25 +03:00
parent 26ac6bd887
commit 9ad3922c7d
10 changed files with 75 additions and 46 deletions
@@ -19,7 +19,7 @@
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-maven-serialization-plugin</artifactId>
<packaging>jar</packaging>
<version>0.5.0</version>
<version>0.5.2-SNAPSHOT</version>
<description>Serialization plugin for Maven</description>
<repositories>
@@ -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"
}
@@ -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`
@@ -1,7 +1,7 @@
<idea-plugin url="https://github.com/Kotlin/kotlinx.serialization" >
<name>Kotlin-serialization</name>
<id>org.jetbrains.kotlinx.serialization</id>
<version>0.5.0</version>
<version>0.5.2-SNAPSHOT</version>
<depends>org.jetbrains.kotlin</depends>
<idea-version since-build="172"/>
@@ -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
@@ -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())
}
}
@@ -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, "<init>", 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<ValueArgument>,
ctorParams: List<ValueParameterDescriptor>
) {
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, "<init>", sb.toString(), false)
}
}
private fun InstructionAdapter.serialCLassDescToLocalVar(classDescVar: Int) {
getstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
store(classDescVar, descType)
@@ -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<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
annotations.asSequence()
.filter { it.type.toClassDescriptor?.annotations?.hasAnnotation(serialInfoFqName) == true }
.filterIsInstance<LazyAnnotationDescriptor>()
.mapNotNull { annDesc ->
annDesc.type.toClassDescriptor?.let {
Triple(it, annDesc.annotationEntry.valueArguments, it.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty())
}
}
.toList()
@@ -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
}
@@ -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<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
descriptor.annotations.asSequence()
.filter { it.type.toClassDescriptor?.annotations?.hasAnnotation(serialInfoFqName) == true }
.filterIsInstance<LazyAnnotationDescriptor>()
.mapNotNull { annDesc ->
annDesc.type.toClassDescriptor?.let {
Triple(it, annDesc.annotationEntry.valueArguments, it.unsubstitutedPrimaryConstructor?.valueParameters.orEmpty())
}
}
.toList()
descriptor.annotationsWithArguments()
}