All Downloads are FREE. Search and download functionalities are using the official Maven repository.

se.ansman.kotshi.kapt.AdaptersProcessingStep.kt Maven / Gradle / Ivy

Go to download

An annotations processor that generates Moshi adapters from Kotlin data classes

The newest version!
@file:Suppress("UnstableApiUsage")

package se.ansman.kotshi.kapt

import com.google.auto.common.MoreElements
import com.google.common.collect.SetMultimap
import kotlin.metadata.Modality
import kotlin.metadata.isData
import kotlin.metadata.modality
import se.ansman.kotshi.Errors
import se.ansman.kotshi.JsonDefaultValue
import se.ansman.kotshi.JsonSerializable
import se.ansman.kotshi.KotshiJsonAdapterFactory
import se.ansman.kotshi.Polymorphic
import se.ansman.kotshi.kapt.generators.DataClassAdapterGenerator
import se.ansman.kotshi.kapt.generators.EnumAdapterGenerator
import se.ansman.kotshi.kapt.generators.ObjectAdapterGenerator
import se.ansman.kotshi.kapt.generators.SealedClassAdapterGenerator
import se.ansman.kotshi.model.GeneratedAdapter
import se.ansman.kotshi.model.GeneratedAnnotation
import se.ansman.kotshi.model.GlobalConfig
import javax.annotation.processing.Filer
import javax.annotation.processing.Messager
import javax.annotation.processing.RoundEnvironment
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind
import javax.lang.model.element.Modifier
import javax.lang.model.element.NestingKind
import javax.lang.model.util.Elements
import javax.lang.model.util.Types

class AdaptersProcessingStep(
    override val processor: KotshiProcessor,
    private val metadataAccessor: MetadataAccessor,
    private val messager: Messager,
    override val filer: Filer,
    private val adapters: MutableList>,
    private val types: Types,
    private val elements: Elements,
    private val generatedAnnotation: GeneratedAnnotation?,
) : KotshiProcessor.GeneratingProcessingStep() {
    override val annotations: Set> =
        setOf(
            Polymorphic::class.java,
            JsonDefaultValue::class.java,
            JsonSerializable::class.java,
            KotshiJsonAdapterFactory::class.java
        )

    override fun process(
        elementsByAnnotation: SetMultimap, Element>,
        roundEnv: RoundEnvironment
    ) {
        for (element in elementsByAnnotation[Polymorphic::class.java]) {
            if (element.getAnnotation(JsonSerializable::class.java) == null) {
                messager.logKotshiError(Errors.polymorphicClassMustHaveJsonSerializable, element)
            }
        }

        for (element in elementsByAnnotation[JsonDefaultValue::class.java]) {
            when (element.kind) {
                ElementKind.ENUM_CONSTANT -> {
                    // Ok
                }
                ElementKind.CLASS -> {
                    val metadata = metadataAccessor.getKmClass(element)
                    if (!metadata.isObject && !metadata.isData) {
                        messager.logKotshiError(Errors.jsonDefaultValueAppliedToInvalidType, element)
                    }

                }
                else -> messager.logKotshiError(Errors.jsonDefaultValueAppliedToInvalidType, element)
            }
        }

        val globalConfig = (elementsByAnnotation[KotshiJsonAdapterFactory::class.java]
            .firstOrNull()
            ?.getAnnotation(KotshiJsonAdapterFactory::class.java)
            ?.let(::GlobalConfig)
            ?: GlobalConfig.DEFAULT)

        for (element in elementsByAnnotation[JsonSerializable::class.java]) {
            try {
                val metadata = metadataAccessor.getKmClass(element)
                val typeElement = MoreElements.asType(element)
                when (typeElement.nestingKind!!) {
                    NestingKind.MEMBER ->
                        if (Modifier.STATIC !in typeElement.modifiers) {
                            throw KaptProcessingError(Errors.dataClassCannotBeInner, typeElement)
                        }

                    NestingKind.TOP_LEVEL -> {
                        // Allowed
                    }

                    NestingKind.ANONYMOUS,
                    NestingKind.LOCAL -> throw KaptProcessingError(Errors.dataClassCannotBeLocal, typeElement)
                }

                val generator = when {
                    metadata.isObject -> ObjectAdapterGenerator(
                        metadataAccessor = metadataAccessor,
                        types = types,
                        element = typeElement,
                        metadata = metadata,
                        elements = elements,
                        globalConfig = globalConfig,
                        messager = messager,
                    )

                    metadata.isData -> DataClassAdapterGenerator(
                        metadataAccessor = metadataAccessor,
                        types = types,
                        elements = elements,
                        element = typeElement,
                        metadata = metadata,
                        globalConfig = globalConfig,
                        messager = messager,
                    )

                    metadata.isEnum -> EnumAdapterGenerator(
                        metadataAccessor = metadataAccessor,
                        types = types,
                        elements = elements,
                        element = typeElement,
                        metadata = metadata,
                        globalConfig = globalConfig,
                        messager = messager
                    )

                    metadata.modality == Modality.SEALED -> SealedClassAdapterGenerator(
                        metadataAccessor = metadataAccessor,
                        types = types,
                        element = typeElement,
                        metadata = metadata,
                        elements = elements,
                        globalConfig = globalConfig,
                        messager = messager
                    )

                    else -> throw KaptProcessingError(Errors.unsupportedSerializableType, typeElement)
                }

                adapters += generator.generateAdapter(
                    generatedAnnotation = generatedAnnotation,
                    filer = filer,
                )
            } catch (e: KaptProcessingError) {
                messager.logKotshiError(e)
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy