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

io.javalin.openapi.experimental.ClassDefinitionApi.kt Maven / Gradle / Ivy

package io.javalin.openapi.experimental

import io.javalin.openapi.experimental.StructureType.ARRAY
import io.javalin.openapi.experimental.StructureType.DEFAULT
import io.javalin.openapi.experimental.StructureType.DICTIONARY
import io.javalin.openapi.experimental.processor.shared.collectionType
import io.javalin.openapi.experimental.processor.shared.mapType
import io.javalin.openapi.experimental.processor.shared.objectType
import javax.lang.model.element.Element
import javax.lang.model.type.ArrayType
import javax.lang.model.type.DeclaredType
import javax.lang.model.type.PrimitiveType
import javax.lang.model.type.TypeMirror
import javax.lang.model.type.TypeVariable

class ClassDefinition(
    val context: AnnotationProcessorContext,
    val mirror: TypeMirror,
    val source: Element,
    val generics: List = emptyList(),
    val structureType: StructureType = DEFAULT,
    val extra: MutableList = mutableListOf()
) {

    val simpleName: String = context.inContext { mirror.getSimpleName() }
    val fullName: String = context.inContext { mirror.getFullName() }

    companion object {

        @JvmStatic
        fun classDefinitionFrom(
            context: AnnotationProcessorContext,
            mirror: TypeMirror,
            generics: List = emptyList(),
            type: StructureType = DEFAULT
        ): ClassDefinition =
            with(context) {
                with (mirror) {
                    when (this) {
                        is TypeVariable ->
                            upperBound?.toClassDefinition(generics, type) ?: lowerBound?.toClassDefinition(generics, type)
                        is ArrayType ->
                            componentType.toClassDefinition(generics, type = ARRAY)
                        is PrimitiveType ->
                            ClassDefinition(
                                context = context,
                                mirror = types.boxedClass(this).asType(),
                                source = types.boxedClass(this),
                                generics = generics,
                                structureType = type
                            )
                        is DeclaredType ->
                            when {
                                types.isAssignable(types.erasure(this), mapType().asType()) ->
                                    ClassDefinition(
                                        context = context,
                                        mirror = this,
                                        source = mapType(),
                                        generics = listOfNotNull(
                                            typeArguments.getOrElse(0) { objectType().asType() }.toClassDefinition(),
                                            typeArguments.getOrElse(1) { objectType().asType() }.toClassDefinition()
                                        ),
                                        structureType = DICTIONARY
                                    )
                                types.isAssignable(types.erasure(this), collectionType().asType()) ->
                                    typeArguments.getOrElse(0) { objectType().asType() }.toClassDefinition(generics, ARRAY)
                                else ->
                                    ClassDefinition(
                                        context = context,
                                        mirror = this,
                                        source = asElement(),
                                        generics = typeArguments.mapNotNull { it.toClassDefinition() },
                                        structureType = type
                                    )
                            }
                        else ->
                            types.asElement(this)?.asType()?.toClassDefinition(generics, type)
                    }
                } ?: objectType().asType().toClassDefinition(type = type)
            }

    }

    override fun equals(other: Any?): Boolean =
        when {
            this === other -> true
            other is ClassDefinition -> this.fullName == other.fullName
            else -> false
        }

    override fun hashCode(): Int = fullName.hashCode()

}

enum class StructureType {
    DEFAULT,
    ARRAY,
    DICTIONARY
}

interface Extra

class CustomProperty(
    val name: String,
    val type: ClassDefinition
) : Extra




© 2015 - 2024 Weber Informatics LLC | Privacy Policy