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

gsonpath.adapter.standard.adapter.AdapterModelMetadataFactory.kt Maven / Gradle / Ivy

Go to download

An annotation processor which generates Type Adapters for the Google Gson library

There is a newer version: 4.0.0
Show newest version
package gsonpath.adapter.standard.adapter

import com.squareup.javapoet.ClassName
import gsonpath.AutoGsonAdapter
import gsonpath.adapter.standard.adapter.properties.AutoGsonAdapterPropertiesFactory
import gsonpath.adapter.standard.adapter.read.ReadParams
import gsonpath.adapter.standard.adapter.write.WriteParams
import gsonpath.adapter.standard.interf.ModelInterfaceGenerator
import gsonpath.adapter.standard.model.FieldInfoFactory
import gsonpath.adapter.standard.model.GsonObjectMetadata
import gsonpath.adapter.standard.model.GsonObjectTreeFactory
import gsonpath.adapter.standard.model.MandatoryFieldInfoFactory
import gsonpath.compiler.generateClassName
import gsonpath.model.FieldInfo
import gsonpath.util.TypeHandler
import javax.lang.model.element.ElementKind
import javax.lang.model.element.TypeElement
import javax.lang.model.type.ExecutableType

class AdapterModelMetadataFactory(
        private val fieldInfoFactory: FieldInfoFactory,
        private val gsonObjectTreeFactory: GsonObjectTreeFactory,
        private val typeHandler: TypeHandler,
        private val modelInterfaceGenerator: ModelInterfaceGenerator) {

    fun createMetadata(modelElement: TypeElement,
                       autoGsonAnnotation: AutoGsonAdapter): AdapterModelMetadata {

        val modelClassName = ClassName.get(modelElement)
        val adapterClassName = ClassName.get(modelClassName.packageName(),
                generateClassName(modelClassName, "GsonTypeAdapter"))

        val concreteClassName: ClassName
        val fieldInfoList: List
        val isModelInterface = modelElement.kind.isInterface

        val properties = AutoGsonAdapterPropertiesFactory().create(modelElement, autoGsonAnnotation, isModelInterface)

        val requiresConstructorInjection: Boolean =
                if (isModelInterface) {
                    true
                } else {
                    findNonEmptyConstructor(modelElement) != null
                }

        val adapterGenericTypeClassNames: List

        if (!isModelInterface) {
            concreteClassName = modelClassName
            adapterGenericTypeClassNames = listOf(modelClassName)

            fieldInfoList = fieldInfoFactory.getModelFieldsFromElement(
                    modelElement,
                    properties.fieldsRequireAnnotation,
                    requiresConstructorInjection)

        } else {
            val interfaceInfo = modelInterfaceGenerator.handle(modelElement)
            concreteClassName = interfaceInfo.parentClassName
            adapterGenericTypeClassNames = listOf(interfaceInfo.parentClassName, modelClassName)

            fieldInfoList = fieldInfoFactory.getModelFieldsFromInterface(interfaceInfo)
        }

        val gsonTreeResult = gsonObjectTreeFactory
                .createGsonObject(fieldInfoList, properties.rootField,
                        GsonObjectMetadata(properties.flattenDelimiter,
                                properties.gsonFieldNamingPolicy,
                                properties.gsonFieldValidationType,
                                properties.pathSubstitutions))

        val rootObject = gsonTreeResult.rootObject
        val flattenedFields = gsonTreeResult.flattenedFields
        val mandatoryInfoMap = MandatoryFieldInfoFactory().createMandatoryFieldsFromGsonObject(rootObject)

        val readParams = ReadParams(
                baseElement = modelClassName,
                concreteElement = concreteClassName,
                requiresConstructorInjection = requiresConstructorInjection,
                mandatoryInfoMap = mandatoryInfoMap,
                rootElements = rootObject,
                flattenedFields = flattenedFields)

        val writeParams = WriteParams(
                elementClassName = modelClassName,
                rootElements = rootObject,
                serializeNulls = properties.serializeNulls)

        return AdapterModelMetadata(
                modelClassName,
                adapterGenericTypeClassNames,
                adapterClassName,
                isModelInterface,
                rootObject,
                mandatoryInfoMap,
                readParams,
                writeParams)
    }

    /**
     * Finds a constructor within the input [TypeElement] that has at least one argument.
     *
     * @param modelElement the model being searched.
     */
    private fun findNonEmptyConstructor(modelElement: TypeElement): ExecutableType? {
        return typeHandler.getAllMembers(modelElement)
                .asSequence()
                .filter { it.kind == ElementKind.CONSTRUCTOR }
                .map { (it.asType() as ExecutableType) }
                .find { it.parameterTypes.size > 0 }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy