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

internal.gen.mapper.MapperGenerator.kt Maven / Gradle / Ivy

package com.mybatisflex.kotlin.ksp.internal.gen.mapper

import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.mybatisflex.kotlin.ksp.internal.config.flex.MapperAnnotation
import com.mybatisflex.kotlin.ksp.internal.config.flex.MapperBaseClass
import com.mybatisflex.kotlin.ksp.internal.util.*
import com.mybatisflex.kotlin.ksp.logger
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.plusParameter
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.ksp.toClassName
import org.apache.ibatis.annotations.Mapper
import java.nio.charset.Charset


internal class MapperGenerator(private val mapperDeclaration: KSClassDeclaration) {
    private val superTypeParam = mapperDeclaration.superTypes.firstOrNull()?.element?.typeArguments?.firstOrNull()

    private val mapperClassName = mapperDeclaration.toClassName()

    /**
     * 执行此方法后,立即生成 Mapper 类。
     * @param classDeclaration 要生成 Mapper 的类声明。
     * @author CloudPlayer
     */
    operator fun invoke(classDeclaration: KSClassDeclaration) {
        if (MapperBaseClass.isOriginalBaseMapper || mapperClassName == BASE_MAPPER) {
            return generateMapper(classDeclaration, BASE_MAPPER.plusParameter(classDeclaration.toClassName()))
        }
        generateTypedMapper(classDeclaration)
    }

    /**
     * 生成 Mapper,仅适用于没有泛型或泛型只有一个的情形。
     *
     * @param classDeclaration 要生成 Mapper 的实体类。
     * @param className Mapper 要继承的接口。如果接口有一个泛型,那么该泛型参数将是实体类的类型。
     */
    private fun generateMapper(classDeclaration: KSClassDeclaration, className: TypeName) {
        val interfaceName = classDeclaration.interfaceName
        val fileSpec = FileSpec.builder(classDeclaration.mapperPackageName, interfaceName)
        fileSpec.addType(
            TypeSpec.interfaceBuilder(
                ClassName(classDeclaration.mapperPackageName, interfaceName)
            ).apply {
                addSuperinterface(className)
                addKdoc("""Mapper for [${classDeclaration.simpleName.asString()}], automatically generated by the ksp of mybatis-flex.""")
                if (MapperAnnotation.value) {
                    addAnnotation(Mapper::class)
                }
            }.build()
        )
            .suppressDefault()
            .build()
            .write(false, classDeclaration.containingFile)
    }

    /**
     * 生成 Mapper,适用于有泛型的情形。
     * @param classDeclaration 对应的泛型,即需要生成 Mapper 的实体类。
     */
    private fun generateTypedMapper(classDeclaration: KSClassDeclaration) {
        val typeParams = mapperDeclaration.typeParameters
        if (typeParams.isEmpty()) {
            generateMapper(classDeclaration, mapperDeclaration.toClassName())
        }
        if (typeParams.size == 1) {
            val typeParam = typeParams[0]
            val thisType = typeParam.name.asString()  // 获取自定义父类的泛型名称。
            // 获取父类在继承 BaseMapper 时使用的泛型。列表中的第一个元素表示其为逆变。
            val superTypeParam = superTypeParam ?: kotlin.run {
                val exception =
                    IllegalArgumentException("Custom Mapper parent classes must inherit from $BASE_MAPPER, not ${mapperDeclaration.toClassName()}")
                logger.exception(exception)
                throw IllegalArgumentException()
            }
            val superType = superTypeParam.toString().split(" ")[1]
            if (thisType == superType) {
                generateMapper(classDeclaration, mapperDeclaration.toClassName().plusParameter(classDeclaration.toClassName()))
            } else {
                logger.exception(
                    UnsupportedOperationException(
                        """
                    |要想在自定义的 Mapper 中使用泛型,你需要保证此 Mapper 直接继承至 BaseMapper ,此外
                    |你需要保证自定义的 Mapper 中携带的泛型直接传递至 BaseMapper 中的泛型,且泛型名称一致。
                    |你在自定义 Mapper 中携带的泛型: $thisType,你在继承 BaseMapper 时使用的泛型: $superType
                    |
                    |你的代码:
                    |       $mapperDeclaration<$thisType> : BaseMapper<$superType>
                    |你需要让代码看起来像这样,让二者的泛型一致:
                    |       $mapperDeclaration<$thisType> : BaseMapper<$thisType>
                """.toByteArray(Charsets.UTF_8).toString(Charset.defaultCharset()).trimMargin()
                    )
                )
            }
        } else logger.exception(UnsupportedOperationException("自定义 Mapper 泛型尚不支持多于一个的泛型。"))
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy