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

se.ansman.kotshi.Property.kt Maven / Gradle / Ivy

Go to download

An annotations processor that generates Moshi adapters from Kotlin data classes

There is a newer version: 3.0.0
Show newest version
package se.ansman.kotshi

import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.ParameterSpec
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeSpec
import se.ansman.kotshi.generators.GlobalConfig
import javax.lang.model.element.ElementKind
import javax.lang.model.element.Modifier
import javax.lang.model.element.TypeElement
import javax.lang.model.util.Elements

class Property private constructor(
    val name: String,
    val type: TypeName,
    val jsonName: String,
    val adapterKey: AdapterKey,
    val hasDefaultValue: Boolean,
    val shouldUseAdapter: Boolean,
    val isTransient: Boolean
) {

    companion object {
        fun create(
            elements: Elements,
            typeSpec: TypeSpec,
            globalConfig: GlobalConfig,
            enclosingClass: TypeElement,
            parameter: ParameterSpec
        ): Property {
            val name = parameter.name
            val type = parameter.type.unwrapTypeAlias()

            val adapterKey = AdapterKey(
                type = type.copy(nullable = false, annotations = emptyList()),
                jsonQualifiers = parameter.annotations.qualifiers(elements)
            )

            val useAdaptersForPrimitives = when (enclosingClass.getAnnotation(JsonSerializable::class.java).useAdaptersForPrimitives) {
                PrimitiveAdapters.DEFAULT -> globalConfig.useAdaptersForPrimitives
                PrimitiveAdapters.ENABLED -> true
                PrimitiveAdapters.DISABLED -> false
            }

            val property = typeSpec.propertySpecs.find { it.name == name }
                ?: throw ProcessingError("Could not find property for parameter $name", enclosingClass)

            val field = enclosingClass.enclosedElements
                .asSequence()
                .filter { it.kind == ElementKind.FIELD && Modifier.STATIC !in it.modifiers }
                .find { it.simpleName.contentEquals(name) }


            KModifier.PRIVATE in property.modifiers || KModifier.PROTECTED in property.modifiers
            if (KModifier.PRIVATE in property.modifiers || KModifier.PROTECTED in property.modifiers) {
                throw ProcessingError("Property $name must be public or internal", enclosingClass)
            }

            val isTransient = Modifier.TRANSIENT in field?.modifiers ?: emptySet()

            if (isTransient && parameter.defaultValue == null) {
                throw ProcessingError("Transient property $name must declare a default value", enclosingClass)
            }

            return Property(
                name = name,
                type = type,
                jsonName = parameter.annotations.jsonName()
                    ?: property.annotations.jsonName()
                    ?: name,
                adapterKey = adapterKey,
                hasDefaultValue = parameter.defaultValue != null,
                shouldUseAdapter = useAdaptersForPrimitives ||
                    adapterKey.jsonQualifiers.isNotEmpty() ||
                    !type.notNull().isPrimitive && type.notNull() != STRING,
                isTransient = isTransient
            )
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy