Custom-serializable enums for JVM
This commit is contained in:
+1
-2
@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
|
||||
import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
|
||||
@@ -30,7 +29,7 @@ abstract class SerializerCodegen(
|
||||
bindingContext: BindingContext
|
||||
) : AbstractSerialGenerator(bindingContext, serializerDescriptor) {
|
||||
val serializableDescriptor: ClassDescriptor = getSerializableClassDescriptorBySerializer(serializerDescriptor)!!
|
||||
protected val serialName: String = serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
||||
protected val serialName: String = serializableDescriptor.serialName()
|
||||
protected val properties = bindingContext.serializablePropertiesFor(serializableDescriptor)
|
||||
protected val serializableProperties = properties.serializableProperties
|
||||
|
||||
|
||||
+8
-2
@@ -96,7 +96,11 @@ fun AbstractSerialGenerator.getSerialTypeInfo(property: SerializableProperty): S
|
||||
|
||||
fun KotlinType.serialName(): String {
|
||||
val serializableDescriptor = this.toClassDescriptor!!
|
||||
return serializableDescriptor.annotations.serialNameValue ?: serializableDescriptor.fqNameUnsafe.asString()
|
||||
return serializableDescriptor.serialName()
|
||||
}
|
||||
|
||||
fun ClassDescriptor.serialName(): String {
|
||||
return annotations.serialNameValue ?: fqNameUnsafe.asString()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,7 +210,9 @@ fun findStandardKotlinTypeSerializer(module: ModuleDescriptor, kType: KotlinType
|
||||
|
||||
fun findEnumTypeSerializer(module: ModuleDescriptor, kType: KotlinType): ClassDescriptor? {
|
||||
val classDescriptor = kType.toClassDescriptor ?: return null
|
||||
return if (classDescriptor.kind == ClassKind.ENUM_CLASS) module.findClassAcrossModuleDependencies(enumSerializerId) else null
|
||||
return if (classDescriptor.kind == ClassKind.ENUM_CLASS && !classDescriptor.isSerializableEnum())
|
||||
module.findClassAcrossModuleDependencies(enumSerializerId)
|
||||
else null
|
||||
}
|
||||
|
||||
internal fun KtPureClassOrObject.bodyPropertiesDescriptorsMap(
|
||||
|
||||
+2
-1
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
||||
|
||||
@@ -176,7 +177,7 @@ class SerializableIrGenerator(
|
||||
SerializableIrGenerator(irClass, context, bindingContext).generate()
|
||||
irClass.patchDeclarationParents(irClass.parent)
|
||||
}
|
||||
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
||||
else if (serializableClass.serializableAnnotationIsUseless) {
|
||||
throw CompilationException(
|
||||
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
||||
"Provide serializer manually via e.g. companion object", null, serializableClass.findPsi()
|
||||
|
||||
+2
-1
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.SerializableCodegen
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.anonymousInitializers
|
||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MISSING_FIELD_EXC
|
||||
|
||||
@@ -164,7 +165,7 @@ class SerializableJsTranslator(
|
||||
) {
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableJsTranslator(declaration, serializableClass, context).generate()
|
||||
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
||||
else if (serializableClass.serializableAnnotationIsUseless) {
|
||||
throw CompilationException(
|
||||
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
||||
"Provide serializer manually via e.g. companion object", null, serializableClass.findPsi()
|
||||
|
||||
+2
@@ -38,6 +38,7 @@ import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.MI
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_CTOR_MARKER_NAME
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_CLASS_IMPL
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_DESCRIPTOR_FOR_ENUM
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_EXC
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_LOADER_CLASS
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.SerialEntityNames.SERIAL_SAVER_CLASS
|
||||
@@ -53,6 +54,7 @@ import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
// todo: extract packages constants too?
|
||||
internal val descType = Type.getObjectType("kotlinx/serialization/$SERIAL_DESCRIPTOR_CLASS")
|
||||
internal val descImplType = Type.getObjectType("kotlinx/serialization/internal/$SERIAL_DESCRIPTOR_CLASS_IMPL")
|
||||
internal val descriptorForEnumsType = Type.getObjectType("kotlinx/serialization/internal/$SERIAL_DESCRIPTOR_FOR_ENUM")
|
||||
internal val generatedSerializerType = Type.getObjectType("kotlinx/serialization/internal/${SerialEntityNames.GENERATED_SERIALIZER_CLASS}")
|
||||
internal val kOutputType = Type.getObjectType("kotlinx/serialization/$STRUCTURE_ENCODER_CLASS")
|
||||
internal val encoderType = Type.getObjectType("kotlinx/serialization/$ENCODER_CLASS")
|
||||
|
||||
+2
-1
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassOrAny
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlinx.serialization.compiler.backend.common.*
|
||||
import org.jetbrains.kotlinx.serialization.compiler.diagnostic.serializableAnnotationIsUseless
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.*
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
@@ -45,7 +46,7 @@ class SerializableCodegenImpl(
|
||||
val serializableClass = codegen.descriptor
|
||||
if (serializableClass.isInternalSerializable)
|
||||
SerializableCodegenImpl(codegen).generate()
|
||||
else if (serializableClass.hasSerializableAnnotationWithoutArgs && !serializableClass.hasCompanionObjectAsSerializer) {
|
||||
else if (serializableClass.serializableAnnotationIsUseless) {
|
||||
throw CompilationException(
|
||||
"@Serializable annotation on $serializableClass would be ignored because it is impossible to serialize it automatically. " +
|
||||
"Provide serializer manually via e.g. companion object", null, serializableClass.findPsi()
|
||||
|
||||
+40
-30
@@ -18,6 +18,7 @@ package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.psi.ValueArgument
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
@@ -29,16 +30,16 @@ import org.jetbrains.org.objectweb.asm.Opcodes.*
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
|
||||
class SerializerCodegenImpl(
|
||||
private val codegen: ImplementationBodyCodegen,
|
||||
open class SerializerCodegenImpl(
|
||||
protected val codegen: ImplementationBodyCodegen,
|
||||
serializableClass: ClassDescriptor
|
||||
) : SerializerCodegen(codegen.descriptor, codegen.bindingContext) {
|
||||
|
||||
|
||||
private val serialDescField = "\$\$serialDesc"
|
||||
|
||||
private val serializerAsmType = codegen.typeMapper.mapClass(codegen.descriptor)
|
||||
private val serializableAsmType = codegen.typeMapper.mapClass(serializableClass)
|
||||
protected val serializerAsmType = codegen.typeMapper.mapClass(codegen.descriptor)
|
||||
protected val serializableAsmType = codegen.typeMapper.mapClass(serializableClass)
|
||||
|
||||
// if we have type parameters, descriptor initializing must be performed in constructor
|
||||
private val staticDescriptor = serializableDescriptor.declaredTypeParameters.isEmpty()
|
||||
@@ -46,7 +47,12 @@ class SerializerCodegenImpl(
|
||||
companion object {
|
||||
fun generateSerializerExtensions(codegen: ImplementationBodyCodegen) {
|
||||
val serializableClass = getSerializableClassDescriptorBySerializer(codegen.descriptor) ?: return
|
||||
SerializerCodegenImpl(codegen, serializableClass).generate()
|
||||
val serializerCodegen = if (serializableClass.isSerializableEnum()) {
|
||||
SerializerForEnumsCodegen(codegen, serializableClass)
|
||||
} else {
|
||||
SerializerCodegenImpl(codegen, serializableClass)
|
||||
}
|
||||
serializerCodegen.generate()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +80,23 @@ class SerializerCodegenImpl(
|
||||
}
|
||||
|
||||
private fun ExpressionCodegen.generateSerialDescriptor(descriptorVar: Int, isStatic: Boolean) = with(v) {
|
||||
instantiateNewDescriptor(isStatic)
|
||||
store(descriptorVar, descImplType)
|
||||
// add contents
|
||||
addElementsContentToDescriptor(descriptorVar)
|
||||
// add annotations on class itself
|
||||
addSyntheticAnnotationsToDescriptor(descriptorVar, serializableDescriptor, CallingConventions.addClassAnnotation)
|
||||
if (isStatic) {
|
||||
load(descriptorVar, descImplType)
|
||||
putstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
|
||||
} else {
|
||||
load(0, serializerAsmType)
|
||||
load(descriptorVar, descImplType)
|
||||
putfield(serializerAsmType.internalName, serialDescField, descType.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun ExpressionCodegen.instantiateNewDescriptor(isStatic: Boolean) = with(v) {
|
||||
anew(descImplType)
|
||||
dup()
|
||||
aconst(serialName)
|
||||
@@ -88,7 +111,9 @@ class SerializerCodegenImpl(
|
||||
load(0, serializerAsmType)
|
||||
}
|
||||
invokespecial(descImplType.internalName, "<init>", "(Ljava/lang/String;${generatedSerializerType.descriptor})V", false)
|
||||
store(descriptorVar, descImplType)
|
||||
}
|
||||
|
||||
protected open fun ExpressionCodegen.addElementsContentToDescriptor(descriptorVar: Int) = with(v) {
|
||||
for (property in serializableProperties) {
|
||||
if (property.transient) continue
|
||||
load(descriptorVar, descImplType)
|
||||
@@ -96,39 +121,24 @@ class SerializerCodegenImpl(
|
||||
iconst(if (property.optional) 1 else 0)
|
||||
invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;Z)V", false)
|
||||
// pushing annotations
|
||||
for ((annotationClass, args, consParams) in property.annotationsWithArguments) {
|
||||
addSyntheticAnnotationsToDescriptor(descriptorVar, property.descriptor, CallingConventions.addAnnotation)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun ExpressionCodegen.addSyntheticAnnotationsToDescriptor(descriptorVar: Int, annotated: Annotated, functionToCall: String) =
|
||||
with(v) {
|
||||
for ((annotationClass, args, consParams) in annotated.annotationsWithArguments()) {
|
||||
if (args.size != consParams.size) throw IllegalArgumentException("Can't use arguments with defaults for serializable annotations yet")
|
||||
load(descriptorVar, descImplType)
|
||||
generateSyntheticAnnotationOnStack(annotationClass, args, consParams)
|
||||
invokevirtual(
|
||||
descImplType.internalName,
|
||||
CallingConventions.addAnnotation,
|
||||
functionToCall,
|
||||
"(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(descriptorVar, descImplType)
|
||||
generateSyntheticAnnotationOnStack(annotationClass, args, consParams)
|
||||
invokevirtual(
|
||||
descImplType.internalName,
|
||||
CallingConventions.addClassAnnotation,
|
||||
"(Ljava/lang/annotation/Annotation;)V",
|
||||
false
|
||||
)
|
||||
}
|
||||
if (isStatic) {
|
||||
load(descriptorVar, descImplType)
|
||||
putstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
|
||||
} else {
|
||||
load(0, serializerAsmType)
|
||||
load(descriptorVar, descImplType)
|
||||
putfield(serializerAsmType.internalName, serialDescField, descType.descriptor)
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateSerialDesc() {
|
||||
var flags = ACC_PRIVATE or ACC_FINAL or ACC_SYNTHETIC
|
||||
@@ -168,7 +178,7 @@ class SerializerCodegenImpl(
|
||||
}
|
||||
|
||||
// use null to put value on stack, use number to store it to var
|
||||
private fun InstructionAdapter.stackSerialClassDesc(classDescVar: Int?) {
|
||||
protected fun InstructionAdapter.stackSerialClassDesc(classDescVar: Int?) {
|
||||
if (staticDescriptor)
|
||||
getstatic(serializerAsmType.internalName, serialDescField, descType.descriptor)
|
||||
else {
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package org.jetbrains.kotlinx.serialization.compiler.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.codegen.ExpressionCodegen
|
||||
import org.jetbrains.kotlin.codegen.ImplementationBodyCodegen
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.CallingConventions
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.enumEntries
|
||||
import org.jetbrains.kotlinx.serialization.compiler.resolve.serialNameValue
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
|
||||
class SerializerForEnumsCodegen(
|
||||
codegen: ImplementationBodyCodegen,
|
||||
serializableClass: ClassDescriptor
|
||||
) : SerializerCodegenImpl(codegen, serializableClass) {
|
||||
override fun generateSave(function: FunctionDescriptor) = codegen.generateMethod(function) { _, _ ->
|
||||
// fun save(output: KOutput, obj : T)
|
||||
val outputVar = 1
|
||||
val objVar = 2
|
||||
// output.encodeEnum(descriptor, ordinal)
|
||||
load(outputVar, encoderType)
|
||||
stackSerialClassDesc(null)
|
||||
load(objVar, serializableAsmType)
|
||||
invokevirtual(serializableAsmType.internalName, "ordinal", "()I", false)
|
||||
invokeinterface(encoderType.internalName, "encodeEnum", "(${descType.descriptor}I)V")
|
||||
// return
|
||||
areturn(Type.VOID_TYPE)
|
||||
}
|
||||
|
||||
override fun generateLoad(function: FunctionDescriptor) = codegen.generateMethod(function) { _, _ ->
|
||||
// fun load(input: KInput): T
|
||||
val inputVar = 1
|
||||
val serializableArrayType = Type.getType("[L${serializableAsmType.internalName};")
|
||||
// T.values()
|
||||
invokestatic(serializableAsmType.internalName, "values", "()${serializableArrayType.descriptor}", false)
|
||||
// input.decodeEnum(descriptor)
|
||||
load(inputVar, decoderType)
|
||||
stackSerialClassDesc(null)
|
||||
invokeinterface(decoderType.internalName, "decodeEnum", "(${descType.descriptor})I")
|
||||
// return
|
||||
aload(serializableAsmType)
|
||||
areturn(serializableAsmType)
|
||||
}
|
||||
|
||||
override fun ExpressionCodegen.instantiateNewDescriptor(isStatic: Boolean) = with(v) {
|
||||
anew(descriptorForEnumsType)
|
||||
dup()
|
||||
aconst(serialName)
|
||||
invokespecial(descriptorForEnumsType.internalName, "<init>", "(Ljava/lang/String;)V", false)
|
||||
checkcast(descImplType)
|
||||
}
|
||||
|
||||
override fun ExpressionCodegen.addElementsContentToDescriptor(descriptorVar: Int) = with(v) {
|
||||
val enumEntries = serializableDescriptor.enumEntries()
|
||||
for (entry in enumEntries) {
|
||||
load(descriptorVar, descImplType)
|
||||
// regular .serialName() produces fqName here, which is kinda inconvenient for enum entry
|
||||
val serialName = entry.annotations.serialNameValue ?: entry.name.toString()
|
||||
aconst(serialName)
|
||||
invokevirtual(descImplType.internalName, CallingConventions.addElement, "(Ljava/lang/String;)V", false)
|
||||
// pushing annotations
|
||||
addSyntheticAnnotationsToDescriptor(descriptorVar, entry, CallingConventions.addAnnotation)
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -58,16 +58,18 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
if (!descriptor.hasSerializableAnnotationWithoutArgs) return false
|
||||
|
||||
if (!descriptor.isInternalSerializable && !descriptor.hasCompanionObjectAsSerializer) {
|
||||
if (descriptor.serializableAnnotationIsUseless) {
|
||||
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.SERIALIZABLE_ANNOTATION_IGNORED)
|
||||
return false
|
||||
}
|
||||
|
||||
// check that we can instantiate supertype
|
||||
val superClass = descriptor.getSuperClassOrAny()
|
||||
if (!superClass.isInternalSerializable && superClass.constructors.singleOrNull { it.valueParameters.size == 0 } == null) {
|
||||
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.NON_SERIALIZABLE_PARENT_MUST_HAVE_NOARG_CTOR)
|
||||
return false
|
||||
if (!descriptor.isSerializableEnum()) { // enums are inherited from java.lang.Enum and can't be inherited from other classes
|
||||
val superClass = descriptor.getSuperClassOrAny()
|
||||
if (!superClass.isInternalSerializable && superClass.constructors.singleOrNull { it.valueParameters.size == 0 } == null) {
|
||||
trace.reportOnSerializableAnnotation(descriptor, SerializationErrors.NON_SERIALIZABLE_PARENT_MUST_HAVE_NOARG_CTOR)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -232,3 +234,6 @@ open class SerializationPluginDeclarationChecker : DeclarationChecker {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.serializableAnnotationIsUseless: Boolean
|
||||
get() = hasSerializableAnnotationWithoutArgs && !isInternalSerializable && !hasCompanionObjectAsSerializer && !isSerializableEnum()
|
||||
+3
-4
@@ -18,7 +18,6 @@ package org.jetbrains.kotlinx.serialization.compiler.extensions
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -38,7 +37,7 @@ import java.util.*
|
||||
open class SerializationResolveExtension : SyntheticResolveExtension {
|
||||
override fun getSyntheticNestedClassNames(thisDescriptor: ClassDescriptor): List<Name> = when {
|
||||
thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && thisDescriptor.platform?.isJvm() == true -> listOf(SerialEntityNames.IMPL_NAME)
|
||||
thisDescriptor.isInternalSerializable && !thisDescriptor.hasCompanionObjectAsSerializer ->
|
||||
(thisDescriptor.shouldHaveGeneratedSerializer) && !thisDescriptor.hasCompanionObjectAsSerializer ->
|
||||
listOf(SerialEntityNames.SERIALIZER_CLASS_NAME)
|
||||
else -> listOf()
|
||||
}
|
||||
@@ -58,7 +57,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
|
||||
) {
|
||||
if (thisDescriptor.annotations.hasAnnotation(serialInfoFqName) && name == SerialEntityNames.IMPL_NAME)
|
||||
result.add(KSerializerDescriptorResolver.addSerialInfoImplClass(thisDescriptor, declarationProvider, ctx))
|
||||
else if (thisDescriptor.isInternalSerializable && name == SerialEntityNames.SERIALIZER_CLASS_NAME &&
|
||||
else if (thisDescriptor.shouldHaveGeneratedSerializer && name == SerialEntityNames.SERIALIZER_CLASS_NAME &&
|
||||
result.none { it.name == SerialEntityNames.SERIALIZER_CLASS_NAME }
|
||||
)
|
||||
result.add(KSerializerDescriptorResolver.addSerializerImplClass(thisDescriptor, declarationProvider, ctx))
|
||||
@@ -66,7 +65,7 @@ open class SerializationResolveExtension : SyntheticResolveExtension {
|
||||
}
|
||||
|
||||
override fun getSyntheticCompanionObjectNameIfNeeded(thisDescriptor: ClassDescriptor): Name? =
|
||||
if (thisDescriptor.kind == ClassKind.CLASS && thisDescriptor.annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName))
|
||||
if (thisDescriptor.shouldHaveGeneratedMethodsInCompanion && !thisDescriptor.isSerializableObject)
|
||||
SpecialNames.DEFAULT_NAME_FOR_COMPANION_OBJECT
|
||||
else null
|
||||
|
||||
|
||||
+29
-3
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyAnnotationDescriptor
|
||||
@@ -37,6 +38,7 @@ internal fun isAllowedToHaveAutoGeneratedSerializerMethods(
|
||||
classDescriptor: ClassDescriptor,
|
||||
serializableClassDescriptor: ClassDescriptor
|
||||
): Boolean {
|
||||
if (serializableClassDescriptor.isSerializableEnum()) return true
|
||||
// don't generate automatically anything for enums or interfaces or other strange things
|
||||
if (serializableClassDescriptor.kind != ClassKind.CLASS) return false
|
||||
// it is either GeneratedSerializer implementation
|
||||
@@ -105,7 +107,7 @@ val KotlinType?.toClassDescriptor: ClassDescriptor?
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.shouldHaveGeneratedMethodsInCompanion: Boolean
|
||||
get() = this.isSerializableObject || this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||
get() = this.isSerializableObject || this.isSerializableEnum() || this.kind == ClassKind.CLASS && annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)
|
||||
|
||||
internal val ClassDescriptor.isSerializableObject: Boolean
|
||||
get() = kind == ClassKind.OBJECT && hasSerializableAnnotationWithoutArgs
|
||||
@@ -116,6 +118,30 @@ internal val ClassDescriptor.isInternalSerializable: Boolean //todo normal check
|
||||
return hasSerializableAnnotationWithoutArgs
|
||||
}
|
||||
|
||||
internal fun ClassDescriptor.isSerializableEnum(): Boolean {
|
||||
if (this.kind != ClassKind.ENUM_CLASS) return false
|
||||
if (hasSerializableAnnotationWithoutArgs) return true
|
||||
if (annotations.hasAnySerialAnnotation) return true
|
||||
// check entries
|
||||
for (enumEntry in enumEntries()) {
|
||||
if (enumEntry.annotations.hasAnySerialAnnotation) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
internal val ClassDescriptor.shouldHaveGeneratedSerializer: Boolean get() = isInternalSerializable || isSerializableEnum()
|
||||
|
||||
internal fun ClassDescriptor.enumEntries(): List<ClassDescriptor> {
|
||||
check(this.kind == ClassKind.ENUM_CLASS)
|
||||
return unsubstitutedMemberScope.getContributedDescriptors().asSequence()
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.filter { it.kind == ClassKind.ENUM_ENTRY }
|
||||
.toList()
|
||||
}
|
||||
|
||||
private val Annotations.hasAnySerialAnnotation: Boolean
|
||||
get() = serialNameValue != null || any { it.annotationClass?.isSerialInfoAnnotation == true }
|
||||
|
||||
internal val ClassDescriptor.hasSerializableAnnotationWithoutArgs: Boolean
|
||||
get() {
|
||||
if (!annotations.hasAnnotation(SerializationAnnotations.serializableAnnotationFqName)) return false
|
||||
@@ -152,7 +178,7 @@ internal val ClassDescriptor?.classSerializer: ClassDescriptor?
|
||||
// can infer @Poly?
|
||||
polymorphicSerializerIfApplicableAutomatically()?.let { return it }
|
||||
// default serializable?
|
||||
if (isInternalSerializable) {
|
||||
if (shouldHaveGeneratedSerializer) {
|
||||
// $serializer nested class
|
||||
return this.unsubstitutedMemberScope
|
||||
.getDescriptorsFiltered(nameFilter = { it == SerialEntityNames.SERIALIZER_CLASS_NAME })
|
||||
@@ -194,7 +220,7 @@ internal fun getSerializableClassDescriptorBySerializer(serializerDescriptor: Cl
|
||||
)
|
||||
) return null
|
||||
val classDescriptor = (serializerDescriptor.containingDeclaration as? ClassDescriptor) ?: return null
|
||||
if (!classDescriptor.isInternalSerializable) return null
|
||||
if (!classDescriptor.shouldHaveGeneratedSerializer) return null
|
||||
return classDescriptor
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -55,6 +55,7 @@ object SerialEntityNames {
|
||||
|
||||
const val SERIAL_DESCRIPTOR_CLASS = "SerialDescriptor"
|
||||
const val SERIAL_DESCRIPTOR_CLASS_IMPL = "SerialClassDescImpl"
|
||||
const val SERIAL_DESCRIPTOR_FOR_ENUM = "EnumDescriptor"
|
||||
|
||||
//exceptions
|
||||
const val SERIAL_EXC = "SerializationException"
|
||||
|
||||
Reference in New Issue
Block a user