Semantic change:
Now properties with default values are @Optional by default, and properties without backing fields are @Transient by default.
This commit is contained in:
+24
-28
@@ -18,7 +18,6 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.codegen.*
|
import org.jetbrains.kotlin.codegen.*
|
||||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|
||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi
|
||||||
@@ -36,8 +35,7 @@ import org.jetbrains.org.objectweb.asm.Type
|
|||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
|
|
||||||
class SerializableCodegenImpl(
|
class SerializableCodegenImpl(
|
||||||
private val classCodegen: ImplementationBodyCodegen,
|
private val classCodegen: ImplementationBodyCodegen
|
||||||
serializableClass: ClassDescriptor
|
|
||||||
) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
|
) : SerializableCodegen(classCodegen.descriptor, classCodegen.bindingContext) {
|
||||||
|
|
||||||
private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
|
private val thisAsmType = classCodegen.typeMapper.mapClass(serializableDescriptor)
|
||||||
@@ -46,7 +44,7 @@ class SerializableCodegenImpl(
|
|||||||
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
|
fun generateSerializableExtensions(codegen: ImplementationBodyCodegen) {
|
||||||
val serializableClass = codegen.descriptor
|
val serializableClass = codegen.descriptor
|
||||||
if (serializableClass.isInternalSerializable)
|
if (serializableClass.isInternalSerializable)
|
||||||
SerializableCodegenImpl(codegen, serializableClass).generate()
|
SerializableCodegenImpl(codegen).generate()
|
||||||
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
||||||
throw CompilationException(
|
throw CompilationException(
|
||||||
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
||||||
@@ -96,7 +94,8 @@ class SerializableCodegenImpl(
|
|||||||
val myPropsStart: Int
|
val myPropsStart: Int
|
||||||
if (superClass.isInternalSerializable) {
|
if (superClass.isInternalSerializable) {
|
||||||
myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size
|
myPropsStart = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties.size
|
||||||
val superTypeArguments = serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
|
val superTypeArguments =
|
||||||
|
serializableDescriptor.typeConstructor.supertypes.single { it.toClassDescriptor?.isInternalSerializable == true }.arguments
|
||||||
//super.writeSelf(output, serialDesc)
|
//super.writeSelf(output, serialDesc)
|
||||||
load(thisI, thisAsmType)
|
load(thisI, thisAsmType)
|
||||||
load(outputI, kOutputType)
|
load(outputI, kOutputType)
|
||||||
@@ -108,10 +107,15 @@ class SerializableCodegenImpl(
|
|||||||
load(offsetI + it, kSerializerType)
|
load(offsetI + it, kSerializerType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val superSignature = classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
|
val superSignature =
|
||||||
invokespecial(classCodegen.typeMapper.mapType(superClass).internalName, superSignature.asmMethod.name, superSignature.asmMethod.descriptor, false)
|
classCodegen.typeMapper.mapSignatureSkipGeneric(KSerializerDescriptorResolver.createWriteSelfFunctionDescriptor(superClass))
|
||||||
}
|
invokespecial(
|
||||||
else {
|
classCodegen.typeMapper.mapType(superClass).internalName,
|
||||||
|
superSignature.asmMethod.name,
|
||||||
|
superSignature.asmMethod.descriptor,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
} else {
|
||||||
myPropsStart = 0
|
myPropsStart = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -174,16 +178,9 @@ class SerializableCodegenImpl(
|
|||||||
|
|
||||||
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
private fun InstructionAdapter.doGenerateConstructorImpl(exprCodegen: ExpressionCodegen) {
|
||||||
val seenMask = 1
|
val seenMask = 1
|
||||||
// var propOffset = 2
|
|
||||||
var (propIndex, propOffset) = generateSuperSerializableCall(2)
|
var (propIndex, propOffset) = generateSuperSerializableCall(2)
|
||||||
for (i in propIndex until properties.serializableProperties.size) {
|
for (i in propIndex until properties.serializableProperties.size) {
|
||||||
val prop = properties[i]
|
val prop = properties[i]
|
||||||
if (prop.transient) {
|
|
||||||
if (!needInitProperty(prop)) throw CompilationException("transient without default value", null, null)
|
|
||||||
exprCodegen.genInitProperty(prop)
|
|
||||||
propOffset += prop.asmType.size
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
val propType = prop.asmType
|
val propType = prop.asmType
|
||||||
if (!prop.optional) {
|
if (!prop.optional) {
|
||||||
// primary were validated before constructor call
|
// primary were validated before constructor call
|
||||||
@@ -196,8 +193,7 @@ class SerializableCodegenImpl(
|
|||||||
load(0, thisAsmType)
|
load(0, thisAsmType)
|
||||||
load(propOffset, propType)
|
load(propOffset, propType)
|
||||||
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
putfield(thisAsmType.internalName, prop.descriptor.name.asString(), propType.descriptor)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
genValidateProperty(i) { seenMask }
|
genValidateProperty(i) { seenMask }
|
||||||
val setLbl = Label()
|
val setLbl = Label()
|
||||||
val nextLabel = Label()
|
val nextLabel = Label()
|
||||||
@@ -211,7 +207,11 @@ class SerializableCodegenImpl(
|
|||||||
visitLabel(setLbl)
|
visitLabel(setLbl)
|
||||||
// setting defaultValue
|
// setting defaultValue
|
||||||
if (classCodegen.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, prop.descriptor] != true)
|
if (classCodegen.bindingContext[BindingContext.BACKING_FIELD_REQUIRED, prop.descriptor] != true)
|
||||||
throw CompilationException("Optional properties without backing fields doesn't have much sense, maybe you want transient?", null, getProp(prop))
|
throw CompilationException(
|
||||||
|
"Optional properties without backing fields doesn't have much sense, maybe you want transient?",
|
||||||
|
null,
|
||||||
|
getProp(prop)
|
||||||
|
)
|
||||||
exprCodegen.genInitProperty(prop)
|
exprCodegen.genInitProperty(prop)
|
||||||
visitLabel(nextLabel)
|
visitLabel(nextLabel)
|
||||||
}
|
}
|
||||||
@@ -222,15 +222,15 @@ class SerializableCodegenImpl(
|
|||||||
val serializedProps = properties.serializableProperties.map { it.descriptor }
|
val serializedProps = properties.serializableProperties.map { it.descriptor }
|
||||||
|
|
||||||
(descToProps - serializedProps)
|
(descToProps - serializedProps)
|
||||||
.filter { classCodegen.shouldInitializeProperty(it.value) }
|
.filter { classCodegen.shouldInitializeProperty(it.value) }
|
||||||
.forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) }
|
.forEach { (_, prop) -> classCodegen.initializeProperty(exprCodegen, prop) }
|
||||||
(paramsToProps - serializedProps)
|
(paramsToProps - serializedProps)
|
||||||
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
|
.forEach { (t, u) -> exprCodegen.genInitParam(t, u) }
|
||||||
|
|
||||||
// init blocks
|
// init blocks
|
||||||
// todo: proper order with other initializers
|
// todo: proper order with other initializers
|
||||||
classCodegen.myClass.anonymousInitializers()
|
classCodegen.myClass.anonymousInitializers()
|
||||||
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
|
.forEach { exprCodegen.gen(it, Type.VOID_TYPE) }
|
||||||
areturn(Type.VOID_TYPE)
|
areturn(Type.VOID_TYPE)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,8 +255,7 @@ class SerializableCodegenImpl(
|
|||||||
}
|
}
|
||||||
invokespecial(superType, "<init>", desc, false)
|
invokespecial(superType, "<init>", desc, false)
|
||||||
return 0 to propStartVar
|
return 0 to propStartVar
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val superProps = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties
|
val superProps = SerializableProperties(superClass, classCodegen.bindingContext).serializableProperties
|
||||||
val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps)
|
val creator = buildInternalConstructorDesc(propStartVar, 1, classCodegen, superProps)
|
||||||
invokespecial(superType, "<init>", creator, false)
|
invokespecial(superType, "<init>", creator, false)
|
||||||
@@ -264,9 +263,6 @@ class SerializableCodegenImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun needInitProperty(prop: SerializableProperty) = getProp(prop)?.let { classCodegen.shouldInitializeProperty(it) }
|
|
||||||
?: getParam(prop)?.hasDefaultValue() ?: throw IllegalStateException()
|
|
||||||
|
|
||||||
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
|
private fun ExpressionCodegen.genInitProperty(prop: SerializableProperty) = getProp(prop)?.let {
|
||||||
classCodegen.initializeProperty(this, it)
|
classCodegen.initializeProperty(this, it)
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -19,6 +19,7 @@ package org.jetbrains.kotlinx.serialization.compiler.resolve
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||||
|
import org.jetbrains.kotlin.resolve.hasBackingField
|
||||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||||
|
|
||||||
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
|
class SerializableProperties(private val serializableClass: ClassDescriptor, val bindingContext: BindingContext) {
|
||||||
@@ -40,7 +41,8 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
|||||||
.filterIsInstance<PropertyDescriptor>()
|
.filterIsInstance<PropertyDescriptor>()
|
||||||
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
|
.filter { it.kind == CallableMemberDescriptor.Kind.DECLARATION }
|
||||||
.filter(this::isPropSerializable)
|
.filter(this::isPropSerializable)
|
||||||
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false) }
|
.map { prop -> SerializableProperty(prop, primaryConstructorProperties[prop] ?: false, prop.hasBackingField(bindingContext)) }
|
||||||
|
.filterNot { it.transient }
|
||||||
.partition { primaryConstructorProperties.contains(it.descriptor) }
|
.partition { primaryConstructorProperties.contains(it.descriptor) }
|
||||||
.run {
|
.run {
|
||||||
val supers = serializableClass.getSuperClassNotAny()
|
val supers = serializableClass.getSuperClassNotAny()
|
||||||
@@ -66,7 +68,6 @@ class SerializableProperties(private val serializableClass: ClassDescriptor, val
|
|||||||
serializableProperties.minus(serializableConstructorProperties)
|
serializableProperties.minus(serializableConstructorProperties)
|
||||||
|
|
||||||
val size = serializableProperties.size
|
val size = serializableProperties.size
|
||||||
val indices = serializableProperties.indices
|
|
||||||
operator fun get(index: Int) = serializableProperties[index]
|
operator fun get(index: Int) = serializableProperties[index]
|
||||||
operator fun iterator() = serializableProperties.iterator()
|
operator fun iterator() = serializableProperties.iterator()
|
||||||
|
|
||||||
|
|||||||
+17
-3
@@ -20,18 +20,25 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclarationWithInitializer
|
||||||
|
import org.jetbrains.kotlin.psi.KtParameter
|
||||||
import org.jetbrains.kotlin.psi.ValueArgument
|
import org.jetbrains.kotlin.psi.ValueArgument
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructorParameterWithDefault: Boolean) {
|
class SerializableProperty(
|
||||||
|
val descriptor: PropertyDescriptor,
|
||||||
|
val isConstructorParameterWithDefault: Boolean,
|
||||||
|
hasBackingField: Boolean
|
||||||
|
) {
|
||||||
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
val name = descriptor.annotations.serialNameValue ?: descriptor.name.asString()
|
||||||
val type = descriptor.type
|
val type = descriptor.type
|
||||||
val genericIndex = type.genericIndex
|
val genericIndex = type.genericIndex
|
||||||
val module = descriptor.module
|
val module = descriptor.module
|
||||||
val serializableWith = extractSerializableWith(descriptor.annotations)
|
val serializableWith = extractSerializableWith(descriptor.annotations)
|
||||||
val optional = descriptor.annotations.serialOptional
|
val optional = descriptor.declaresDefaultValue
|
||||||
val transient = descriptor.annotations.serialTransient
|
val transient = descriptor.annotations.serialTransient || !hasBackingField
|
||||||
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
val annotationsWithArguments: List<Triple<ClassDescriptor, List<ValueArgument>, List<ValueParameterDescriptor>>> =
|
||||||
descriptor.annotationsWithArguments()
|
descriptor.annotationsWithArguments()
|
||||||
|
|
||||||
@@ -42,3 +49,10 @@ class SerializableProperty(val descriptor: PropertyDescriptor, val isConstructor
|
|||||||
else null
|
else null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val PropertyDescriptor.declaresDefaultValue: Boolean
|
||||||
|
get() = when (val declaration = this.source.getPsi()) {
|
||||||
|
is KtDeclarationWithInitializer -> declaration.initializer != null
|
||||||
|
is KtParameter -> declaration.defaultValue != null
|
||||||
|
else -> false
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user