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

se.ansman.kotshi.kapt.generators.EnumAdapterGenerator.kt Maven / Gradle / Ivy

package se.ansman.kotshi.kapt.generators

import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.jvm.throws
import com.squareup.kotlinpoet.metadata.ImmutableKmClass
import com.squareup.kotlinpoet.metadata.isEnum
import se.ansman.kotshi.GlobalConfig
import se.ansman.kotshi.kapt.MetadataAccessor
import se.ansman.kotshi.kapt.ProcessingError
import se.ansman.kotshi.addControlFlow
import se.ansman.kotshi.addNextControlFlow
import se.ansman.kotshi.addWhen
import se.ansman.kotshi.jsonName
import se.ansman.kotshi.nullable
import javax.annotation.processing.Messager
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements
import javax.lang.model.util.Types

class EnumAdapterGenerator(
    metadataAccessor: MetadataAccessor,
    types: Types,
    elements: Elements,
    element: TypeElement,
    metadata: ImmutableKmClass,
    globalConfig: GlobalConfig,
    messager: Messager
) : AdapterGenerator(metadataAccessor, types, elements, element, metadata, globalConfig) {
    init {
        require(metadata.isEnum)
    }

    override fun TypeSpec.Builder.addMethods() {
        val enumToJsonName = elementTypeSpec.enumConstants.mapValues { (name, type) ->
            type.annotationSpecs.jsonName() ?: name
        }

        var defaultValue: String? = null
        for ((entry, spec) in elementTypeSpec.enumConstants) {
            if (spec.annotationSpecs.any { it.className == jsonDefaultValue }) {
                if (defaultValue != null) {
                    throw ProcessingError("Only one enum entry can be annotated with @JsonDefaultValue", element)
                }
                defaultValue = entry
            }
        }

        this
            .addFunction(FunSpec.builder("toJson")
                .addModifiers(KModifier.OVERRIDE)
                .throws(ioException)
                .addParameter(writerParameter)
                .addParameter(value)
                .addWhen("%N", value) {
                    for ((entry, name) in enumToJsonName) {
                        addStatement("%T.%N·-> %N.value(%S)", className, entry, writerParameter, name)
                    }
                    addStatement("null·-> %N.nullValue()", writerParameter)
                }
                .build())
            .addFunction(FunSpec.builder("fromJson")
                .addModifiers(KModifier.OVERRIDE)
                .throws(ioException)
                .addParameter(readerParameter)
                .returns(typeName.nullable())
                .addControlFlow("return·if (%N.peek() == %T.NULL)", readerParameter, jsonReaderToken, close = false) {
                    addStatement("%N.nextNull()", readerParameter)
                }
                .addNextControlFlow("else when (%N.selectString(options))", readerParameter) {
                    enumToJsonName.keys.forEachIndexed { index, entry ->
                        addStatement("$index·-> %T.%N", className, entry)
                    }
                    if (defaultValue == null) {
                        addStatement("else·-> throw·%T(%P)", jsonDataException, "Expected one of ${enumToJsonName.values} but was \${${readerParameter.name}.nextString()} at path \${${readerParameter.name}.path}")
                    } else {
                        addControlFlow("else·->") {
                            addStatement("%N.skipValue()", readerParameter)
                            addStatement("%T.%N", className, defaultValue)
                        }
                    }
                }
                .build())
            .maybeAddCompanion(enumToJsonName.values)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy